diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/boot/edd.S linux-2.6.9/arch/i386/boot/edd.S --- linux.vanilla-2.6.9/arch/i386/boot/edd.S 2004-10-20 22:33:24.000000000 +0100 +++ linux-2.6.9/arch/i386/boot/edd.S 2004-11-25 20:20:16.000000000 +0000 @@ -1,5 +1,6 @@ /* * BIOS Enhanced Disk Drive support + * Copyright (C) 2002, 2003, 2004 Dell, Inc. * by Matt Domsch October 2002 * conformant to T13 Committee www.t13.org * projects 1572D, 1484D, 1386D, 1226DT @@ -7,14 +8,52 @@ * and Andrew Wilks September 2003, June 2004 * legacy CHS retreival by Patrick J. LoPresti * March 2004 + * Command line option parsing, Matt Domsch, November 2004 */ #include +#include #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) + movb $0, (EDD_MBR_SIG_NR_BUF) # zero value at EDD_MBR_SIG_NR_BUF + movb $0, (EDDNR) # zero value at EDDNR + +# Check the command line for two options: +# edd=of disables EDD completely (edd=off) +# edd=sk skips the MBR test (edd=skipmbr) + pushl %esi + cmpl $0, %cs:cmd_line_ptr + jz done_cl + movl %cs:(cmd_line_ptr), %esi +# ds:esi has the pointer to the command line now + movl $(COMMAND_LINE_SIZE-6), %ecx +# loop through kernel command line one byte at a time +cl_loop: + cmpl $EDD_CL_EQUALS, (%si) + jz found_edd_equals + incl %esi + loop cl_loop + jmp done_cl +found_edd_equals: +# only looking at first two characters after equals + addl $4, %esi + cmpw $EDD_CL_OFF, (%si) # edd=of + jz do_edd_off + cmpw $EDD_CL_SKIP, (%si) # edd=sk + jz do_edd_skipmbr + jmp done_cl +do_edd_skipmbr: + popl %esi + jmp edd_start +do_edd_off: + popl %esi + jmp edd_done +done_cl: + popl %esi + + # Read the first sector of each BIOS disk device and store the 4-byte signature edd_mbr_sig_start: - movb $0, (EDD_MBR_SIG_NR_BUF) # zero value at EDD_MBR_SIG_NR_BUF movb $0x80, %dl # from device 80 movw $EDD_MBR_SIG_BUF, %bx # store buffer ptr in bx edd_mbr_sig_read: @@ -76,7 +115,6 @@ # result buffer for fn48 movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results # kept just before that - movb $0, (EDDNR) # zero value at EDDNR movb $0x80, %dl # BIOS device 0x80 edd_check_ext: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/boot/video.S linux-2.6.9/arch/i386/boot/video.S --- linux.vanilla-2.6.9/arch/i386/boot/video.S 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/i386/boot/video.S 2004-10-28 00:45:37.000000000 +0100 @@ -1936,7 +1936,7 @@ movl $0x13131313, %eax # memset block with 0x13 movw $32, %cx - movw $0x440, %di + movw $0x140, %di cld rep stosl @@ -1945,7 +1945,7 @@ movw $0x01, %bx movw $0x00, %cx movw $0x01, %dx - movw $0x440, %di + movw $0x140, %di int $0x10 popw %di # restore all registers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/Kconfig linux-2.6.9/arch/i386/Kconfig --- linux.vanilla-2.6.9/arch/i386/Kconfig 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/i386/Kconfig 2004-11-25 23:06:10.000000000 +0000 @@ -199,7 +199,7 @@ bool "586/K5/5x86/6x86/6x86MX" help Select this for an 586 or 686 series processor such as the AMD K5, - the Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not + the Cyrix 5x86, 6x86 and 6x86MX. This choice does not assume the RDTSC (Read Time Stamp Counter) instruction. config M586TSC @@ -324,6 +324,14 @@ endchoice +config X86_HZ + int "Clock Tick Rate" + default 1000 if !(M386 || M486 || M586 || M586TSC || M586MMX) + default 100 if (M386 || M486 || M586 || M586TSC || M586MMX) + help + Select the kernel clock tick rate in interrupts per second. + Slower processors should choose 100; everything else 1000. + config X86_GENERIC bool "Generic x86 support" help diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/kernel/cpu/proc.c linux-2.6.9/arch/i386/kernel/cpu/proc.c --- linux.vanilla-2.6.9/arch/i386/kernel/cpu/proc.c 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/i386/kernel/cpu/proc.c 2004-12-01 21:05:54.000000000 +0000 @@ -88,7 +88,7 @@ if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); #ifdef CONFIG_X86_HT - if (cpu_has_ht) { + if (smp_num_siblings > 1) { extern int phys_proc_id[NR_CPUS]; seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]); seq_printf(m, "siblings\t: %d\n", smp_num_siblings); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/kernel/io_apic.c linux-2.6.9/arch/i386/kernel/io_apic.c --- linux.vanilla-2.6.9/arch/i386/kernel/io_apic.c 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/i386/kernel/io_apic.c 2004-10-28 00:49:59.000000000 +0100 @@ -728,7 +728,7 @@ /* * Find the IRQ entry number of a certain pin. */ -static int __init find_irq_entry(int apic, int pin, int type) +static int find_irq_entry(int apic, int pin, int type) { int i; @@ -838,7 +838,7 @@ /* * EISA Edge/Level control register, ELCR */ -static int __init EISA_ELCR(unsigned int irq) +static int EISA_ELCR(unsigned int irq) { if (irq < 16) { unsigned int port = 0x4d0 + (irq >> 3); @@ -955,7 +955,7 @@ return polarity; } -static int __init MPBIOS_trigger(int idx) +static int MPBIOS_trigger(int idx) { int bus = mp_irqs[idx].mpc_srcbus; int trigger; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/kernel/irq.c linux-2.6.9/arch/i386/kernel/irq.c --- linux.vanilla-2.6.9/arch/i386/kernel/irq.c 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/i386/kernel/irq.c 2004-10-17 00:08:41.000000000 +0100 @@ -275,12 +275,103 @@ static int __init noirqdebug_setup(char *str) { noirqdebug = 1; - printk("IRQ lockup detection disabled\n"); + printk(KERN_INFO "IRQ lockup detection disabled\n"); return 1; } __setup("noirqdebug", noirqdebug_setup); +static int irqfixup; + +static int __init irqfixup_setup(char *str) +{ + irqfixup = 1; + printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n"); + printk(KERN_WARNING "This may impact system performance.\n"); + return 1; +} + +__setup("irqfixup", irqfixup_setup); + +static int __init irqpoll_setup(char *str) +{ + irqfixup = 2; + printk(KERN_WARNING "Misrouted IRQ fixup and polling support enabled.\n"); + printk(KERN_WARNING "This may significantly impact system performance.\n"); + return 1; +} + +__setup("irqpoll", irqpoll_setup); + +/* + * Recovery handler for misrouted interrupts + */ + +static asmlinkage int misrouted_irq(int irq, struct pt_regs *regs) +{ + int i; + irq_desc_t *desc; + int ok = 0; + int work = 0; /* Did we do work for a real IRQ */ + for(i = 1; i < NR_IRQS; i++) + { + struct irqaction *action; + if(i == irq) /* Already tried */ + continue; + desc = &irq_desc[i]; + spin_lock(&desc->lock); + action = desc->action; + /* Already running on another processor */ + if(desc->status & IRQ_INPROGRESS) + { + /* Already running: If it is shared get the other + CPU to go looking for our mystery interrupt too */ + if(desc->action && (desc->action->flags & SA_SHIRQ)) + desc->status |= IRQ_PENDING; + spin_unlock(&desc->lock); + continue; + } + /* Honour the normal IRQ locking */ + desc->status |= IRQ_INPROGRESS; + spin_unlock(&desc->lock); + while(action) + { + /* Only shared IRQ handlers are safe to call */ + if(action->flags & SA_SHIRQ) + { + if(action->handler(i, action->dev_id, regs) == IRQ_HANDLED) + ok = 1; + } + action = action->next; + } + local_irq_disable(); + /* Now clean up the flags */ + spin_lock(&desc->lock); + action = desc->action; + + /* While we were looking for a fixup someone queued a real + IRQ clashing with our walk */ + + while((desc->status & IRQ_PENDING) && action) + { + /* Perform real IRQ processing for the IRQ we deferred */ + work = 1; + spin_unlock(&desc->lock); + handle_IRQ_event(i, regs, action); + spin_lock(&desc->lock); + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + /* If we did actual work for the real IRQ line we must + let the IRQ controller clean up too */ + if(work) + desc->handler->end(i); + spin_unlock(&desc->lock); + } + /* So the caller can adjust the irq error counts */ + return ok; +} + /* * If 99,900 of the previous 100,000 interrupts have not been handled then * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to @@ -291,13 +382,69 @@ * * Called under desc->lock */ -static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) +static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret, struct pt_regs *regs) { if (action_ret != IRQ_HANDLED) { desc->irqs_unhandled++; if (action_ret != IRQ_NONE) report_bad_irq(irq, desc, action_ret); } + if(unlikely(irqfixup)) /* Don't punish working computers */ + { + if((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) + { + int ok; +#ifdef CONFIG_4KSTACKS + u32 *isp; + union irq_ctx * curctx; + union irq_ctx * irqctx; + + curctx = (union irq_ctx *) current_thread_info(); + irqctx = hardirq_ctx[smp_processor_id()]; + + spin_unlock(&desc->lock); + + /* + * this is where we switch to the IRQ stack. However, if we are already using + * the IRQ stack (because we interrupted a hardirq handler) we can't do that + * and just have to keep using the current stack (which is the irq stack already + * after all) + */ + + if (curctx == irqctx) + ok = misrouted_irq(irq, regs); + else { + /* build the stack frame on the IRQ stack */ + isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); + irqctx->tinfo.task = curctx->tinfo.task; + irqctx->tinfo.previous_esp = current_stack_pointer(); + + *--isp = (u32) regs; + *--isp = (u32) irq; + + asm volatile( + " xchgl %%ebx,%%esp \n" + " call misrouted_irq \n" + " xchgl %%ebx,%%esp \n" + : "=a"(ok) + : "b"(isp) + : "memory", "cc", "edx", "ecx" + ); + } + spin_lock(&desc->lock); + if (curctx != irqctx) + irqctx->tinfo.task = NULL; +#else + spin_unlock(&desc->lock); + + ok = misrouted_irq(irq, regs); + + spin_lock(&desc->lock); +#endif + if(action_ret == IRQ_NONE) + desc->irqs_unhandled -= ok; + } + } desc->irq_count++; if (desc->irq_count < 100000) @@ -534,7 +681,7 @@ } spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, ®s); if (curctx != irqctx) irqctx->tinfo.task = NULL; if (likely(!(desc->status & IRQ_PENDING))) @@ -553,7 +700,7 @@ spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, ®s); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/kernel/Makefile linux-2.6.9/arch/i386/kernel/Makefile --- linux.vanilla-2.6.9/arch/i386/kernel/Makefile 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/i386/kernel/Makefile 2004-12-10 20:31:15.000000000 +0000 @@ -33,7 +33,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -EXTRA_AFLAGS := -traditional +EXTRA_AFLAGS := -traditional -m32 obj-$(CONFIG_SCx200) += scx200.o @@ -51,7 +51,7 @@ export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH) -vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 +vsyscall-flags = -m32 -shared -s -Wl,-soname=linux-gate.so.1 SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) @@ -66,6 +66,6 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o -SYSCFLAGS_vsyscall-syms.o = -r +SYSCFLAGS_vsyscall-syms.o = -m32 -r $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE $(call if_changed,syscall) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/i386/kernel/vm86.c linux-2.6.9/arch/i386/kernel/vm86.c --- linux.vanilla-2.6.9/arch/i386/kernel/vm86.c 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/i386/kernel/vm86.c 2004-12-11 15:26:06.345466248 +0000 @@ -721,8 +721,12 @@ if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk) goto out; irqbits |= irq_bit; - if (vm86_irqs[intno].sig) + if (vm86_irqs[intno].sig) { send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1); + disable_irq(intno); + spin_unlock_irqrestore(&irqbits_lock, flags); + return IRQ_HANDLED; + } /* else user will poll for IRQs */ out: spin_unlock_irqrestore(&irqbits_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/ia64/ia32/binfmt_elf32.c linux-2.6.9/arch/ia64/ia32/binfmt_elf32.c --- linux.vanilla-2.6.9/arch/ia64/ia32/binfmt_elf32.c 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/ia64/ia32/binfmt_elf32.c 2004-12-01 21:08:51.000000000 +0000 @@ -100,7 +100,11 @@ vma->vm_ops = &ia32_shared_page_vm_ops; down_write(¤t->mm->mmap_sem); { - insert_vm_struct(current->mm, vma); + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + return; + } } up_write(¤t->mm->mmap_sem); } @@ -123,7 +127,11 @@ vma->vm_ops = &ia32_gate_page_vm_ops; down_write(¤t->mm->mmap_sem); { - insert_vm_struct(current->mm, vma); + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + return; + } } up_write(¤t->mm->mmap_sem); } @@ -142,7 +150,11 @@ vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE; down_write(¤t->mm->mmap_sem); { - insert_vm_struct(current->mm, vma); + if (insert_vm_struct(current->mm, vma)) { + kmem_cache_free(vm_area_cachep, vma); + up_write(¤t->mm->mmap_sem); + return; + } } up_write(¤t->mm->mmap_sem); } @@ -190,7 +202,7 @@ unsigned long stack_base; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; - int i; + int i, ret; stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; mm->arg_start = bprm->p + stack_base; @@ -225,7 +237,11 @@ mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)? PAGE_COPY_EXEC: PAGE_COPY; - insert_vm_struct(current->mm, mpnt); + if ((ret = insert_vm_struct(current->mm, mpnt))) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/ia64/mm/init.c linux-2.6.9/arch/ia64/mm/init.c --- linux.vanilla-2.6.9/arch/ia64/mm/init.c 2004-10-20 23:16:38.000000000 +0100 +++ linux-2.6.9/arch/ia64/mm/init.c 2004-12-01 21:08:51.000000000 +0000 @@ -131,7 +131,13 @@ vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; vma->vm_flags = VM_DATA_DEFAULT_FLAGS | VM_GROWSUP; - insert_vm_struct(current->mm, vma); + down_write(¤t->mm->mmap_sem); + if (insert_vm_struct(current->mm, vma)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return; + } + up_write(¤t->mm->mmap_sem); } /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ @@ -143,7 +149,13 @@ vma->vm_end = PAGE_SIZE; vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED; - insert_vm_struct(current->mm, vma); + down_write(¤t->mm->mmap_sem); + if (insert_vm_struct(current->mm, vma)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return; + } + up_write(¤t->mm->mmap_sem); } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/s390/kernel/compat_exec.c linux-2.6.9/arch/s390/kernel/compat_exec.c --- linux.vanilla-2.6.9/arch/s390/kernel/compat_exec.c 2004-10-20 23:16:39.000000000 +0100 +++ linux-2.6.9/arch/s390/kernel/compat_exec.c 2004-12-01 21:08:51.000000000 +0000 @@ -39,7 +39,7 @@ unsigned long stack_base; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; - int i; + int i, ret; stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; mm->arg_start = bprm->p + stack_base; @@ -68,7 +68,11 @@ /* executable stack setting would be applied here */ mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; - insert_vm_struct(mm, mpnt); + if ((ret = insert_vm_struct(mm, mpnt))) { + up_write(&mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } mm->stack_vm = mm->total_vm = vma_pages(mpnt); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/s390/kernel/traps.c linux-2.6.9/arch/s390/kernel/traps.c --- linux.vanilla-2.6.9/arch/s390/kernel/traps.c 2004-10-20 23:16:39.000000000 +0100 +++ linux-2.6.9/arch/s390/kernel/traps.c 2004-10-28 00:35:27.000000000 +0100 @@ -630,6 +630,21 @@ } } +asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code) +{ + siginfo_t info; + + /* Set user psw back to home space mode. */ + if (regs->psw.mask & PSW_MASK_PSTATE) + regs->psw.mask |= PSW_ASC_HOME; + /* Send SIGILL. */ + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_PRVOPC; + info.si_addr = get_check_address(regs); + do_trap(int_code, SIGILL, "space switch event", regs, &info); +} + asmlinkage void kernel_stack_overflow(struct pt_regs * regs) { die("Kernel stack overflow", regs, 0); @@ -673,7 +688,7 @@ pgm_check_table[0x3B] = &do_dat_exception; #endif /* CONFIG_ARCH_S390X */ pgm_check_table[0x15] = &operand_exception; - pgm_check_table[0x1C] = &privileged_op; + pgm_check_table[0x1C] = &space_switch_exception; pgm_check_table[0x1D] = &hfp_sqrt_exception; pgm_check_table[0x40] = &do_monitor_call; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/x86_64/boot/video.S linux-2.6.9/arch/x86_64/boot/video.S --- linux.vanilla-2.6.9/arch/x86_64/boot/video.S 2004-10-20 23:16:40.000000000 +0100 +++ linux-2.6.9/arch/x86_64/boot/video.S 2004-11-11 15:52:42.000000000 +0000 @@ -1936,7 +1936,7 @@ movl $0x13131313, %eax # memset block with 0x13 movw $32, %cx - movw $0x440, %di + movw $0x140, %di cld rep stosl @@ -1945,7 +1945,7 @@ movw $0x01, %bx movw $0x00, %cx movw $0x01, %dx - movw $0x440, %di + movw $0x140, %di int $0x10 popw %di # restore all registers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/x86_64/ia32/ia32_binfmt.c linux-2.6.9/arch/x86_64/ia32/ia32_binfmt.c --- linux.vanilla-2.6.9/arch/x86_64/ia32/ia32_binfmt.c 2004-10-20 23:16:40.000000000 +0100 +++ linux-2.6.9/arch/x86_64/ia32/ia32_binfmt.c 2004-12-01 21:08:51.000000000 +0000 @@ -333,7 +333,7 @@ unsigned long stack_base; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; - int i; + int i, ret; stack_base = IA32_STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE; mm->arg_start = bprm->p + stack_base; @@ -367,7 +367,11 @@ mpnt->vm_flags = vm_stack_flags32; mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? PAGE_COPY_EXEC : PAGE_COPY; - insert_vm_struct(mm, mpnt); + if ((ret = insert_vm_struct(mm, mpnt))) { + up_write(&mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } mm->stack_vm = mm->total_vm = vma_pages(mpnt); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/x86_64/ia32/sys_ia32.c linux-2.6.9/arch/x86_64/ia32/sys_ia32.c --- linux.vanilla-2.6.9/arch/x86_64/ia32/sys_ia32.c 2004-10-20 23:16:40.000000000 +0100 +++ linux-2.6.9/arch/x86_64/ia32/sys_ia32.c 2004-12-01 21:11:53.000000000 +0000 @@ -658,11 +658,12 @@ int sys32_ni_syscall(int call) { struct task_struct *me = current; - static char lastcomm[8]; - if (strcmp(lastcomm, me->comm)) { - printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call, - current->comm); - strcpy(lastcomm, me->comm); + static char lastcomm[sizeof(me->comm)]; + + if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) { + printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", + call, me->comm); + strncpy(lastcomm, me->comm, sizeof(lastcomm)); } return -ENOSYS; } @@ -1342,11 +1343,11 @@ long sys32_vm86_warning(void) { struct task_struct *me = current; - static char lastcomm[8]; - if (strcmp(lastcomm, me->comm)) { + static char lastcomm[sizeof(me->comm)]; + if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) { printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n", me->comm); - strcpy(lastcomm, me->comm); + strncpy(lastcomm, me->comm, sizeof(lastcomm)); } return -ENOSYS; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/x86_64/kernel/io_apic.c linux-2.6.9/arch/x86_64/kernel/io_apic.c --- linux.vanilla-2.6.9/arch/x86_64/kernel/io_apic.c 2004-10-20 23:16:40.000000000 +0100 +++ linux-2.6.9/arch/x86_64/kernel/io_apic.c 2004-10-28 00:40:34.000000000 +0100 @@ -265,12 +265,14 @@ #endif return; case PCI_VENDOR_ID_NVIDIA: -#ifndef CONFIG_SMP +#ifdef CONFIG_ACPI + /* All timer overrides on Nvidia + seem to be wrong. Skip them. */ + acpi_skip_timer_override = 1; printk(KERN_INFO - "PCI bridge %02x:%02x from %x found. Setting \"noapic\". Overwrite with \"apic\"\n", - num,slot,vendor); - skip_ioapic_setup = 1; + "Nvidia board detected. Ignoring ACPI timer override.\n"); #endif + /* RED-PEN skip them on mptables too? */ return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/arch/x86_64/kernel/setup.c linux-2.6.9/arch/x86_64/kernel/setup.c --- linux.vanilla-2.6.9/arch/x86_64/kernel/setup.c 2004-10-20 23:16:40.000000000 +0100 +++ linux-2.6.9/arch/x86_64/kernel/setup.c 2004-12-01 21:05:54.000000000 +0000 @@ -1132,7 +1132,7 @@ seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); #ifdef CONFIG_X86_HT - if (cpu_has_ht) { + if (smp_num_siblings > 1) { seq_printf(m, "physical id\t: %d\n", phys_proc_id[c - cpu_data]); seq_printf(m, "siblings\t: %d\n", smp_num_siblings); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/Documentation/i386/zero-page.txt linux-2.6.9/Documentation/i386/zero-page.txt --- linux.vanilla-2.6.9/Documentation/i386/zero-page.txt 2004-10-20 22:32:19.000000000 +0100 +++ linux-2.6.9/Documentation/i386/zero-page.txt 2004-10-28 00:45:37.000000000 +0100 @@ -28,7 +28,8 @@ 0xa0 16 bytes System description table truncated to 16 bytes. ( struct sys_desc_table_struct ) - 0xb0 - 0x1c3 Free. Add more parameters here if you really need them. + 0xb0 - 0x13f Free. Add more parameters here if you really need them. + 0x140- 0x1be EDID_INFO Video mode setup 0x1c4 unsigned long EFI system table pointer 0x1c8 unsigned long EFI memory descriptor size diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/Documentation/kernel-parameters.txt linux-2.6.9/Documentation/kernel-parameters.txt --- linux.vanilla-2.6.9/Documentation/kernel-parameters.txt 2004-10-20 23:16:37.000000000 +0100 +++ linux-2.6.9/Documentation/kernel-parameters.txt 2004-11-25 20:20:16.000000000 +0000 @@ -29,6 +29,7 @@ CD Appropriate CD support is enabled. DEVFS devfs support is enabled. DRM Direct Rendering Management support is enabled. + EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled EIDE EIDE/ATAPI support is enabled. FB The frame buffer device is enabled. @@ -391,6 +392,10 @@ edb= [HW,PS2] + edd [EDD] + Format: {"of[f]" | "sk[ipmbr]"} + See comment in arch/i386/boot/edd.S + eicon= [HW,ISDN] Format: ,, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/Documentation/sysctl/kernel.txt linux-2.6.9/Documentation/sysctl/kernel.txt --- linux.vanilla-2.6.9/Documentation/sysctl/kernel.txt 2004-10-20 23:16:37.000000000 +0100 +++ linux-2.6.9/Documentation/sysctl/kernel.txt 2004-10-16 22:13:53.000000000 +0100 @@ -49,6 +49,7 @@ - shmmax [ sysv ipc ] - shmmni - stop-a [ SPARC only ] +- suid_dumpable - sysrq ==> Documentation/sysrq.txt - tainted - threads-max @@ -300,6 +301,25 @@ ============================================================== +suid_dumpable: + +This value can be used to query and set the core dump mode for setuid +or otherwise protected/tainted binaries. The modes are + +0 - (default) - traditional behaviour. Any process which has changed + privilege levels or is execute only will not be dumped +1 - (debug) - all processes dump core when possible. The core dump is + owned by the current user and no security is applied. This is + intended for system debugging situations only. +2 - (suidsafe) - any binary which normally not be dumped is dumped + readable by root only. This allows the end user to remove + such a dump but not access it directly. For security reasons + core dumps in this mode will not overwrite one another or + other files. This mode is appropriate when adminstrators are + attempting to debug problems in a normal environment. + +============================================================== + tainted: Non-zero if the kernel has been tainted. Numeric values, which diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/block/cciss.c linux-2.6.9/drivers/block/cciss.c --- linux.vanilla-2.6.9/drivers/block/cciss.c 2004-10-20 23:16:43.000000000 +0100 +++ linux-2.6.9/drivers/block/cciss.c 2004-12-01 21:15:38.000000000 +0000 @@ -799,7 +799,7 @@ luninfo.num_opens = drv->usage_count; luninfo.num_parts = 0; /* count partitions 1 to 15 with sizes > 0 */ - for(i=1; i part[i]) continue; if (disk->part[i]->nr_sects != 0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/block/scsi_ioctl.c linux-2.6.9/drivers/block/scsi_ioctl.c --- linux.vanilla-2.6.9/drivers/block/scsi_ioctl.c 2004-10-20 23:16:44.000000000 +0100 +++ linux-2.6.9/drivers/block/scsi_ioctl.c 2004-11-08 17:23:44.000000000 +0000 @@ -139,6 +139,7 @@ safe_for_read(GPCMD_PAUSE_RESUME), /* CD/DVD data reading */ + safe_for_read(GPCMD_READ_BUFFER_CAPACITY), safe_for_read(GPCMD_READ_CD), safe_for_read(GPCMD_READ_CD_MSF), safe_for_read(GPCMD_READ_DISC_INFO), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/block/sx8.c linux-2.6.9/drivers/block/sx8.c --- linux.vanilla-2.6.9/drivers/block/sx8.c 2004-10-20 23:16:44.000000000 +0100 +++ linux-2.6.9/drivers/block/sx8.c 2004-12-10 20:47:54.000000000 +0000 @@ -1503,7 +1503,7 @@ } port->disk = disk; - sprintf(disk->disk_name, DRV_NAME "%u_%u", host->id, i); + sprintf(disk->disk_name, DRV_NAME "/%u", (host->id * CARM_MAX_PORTS) + i); sprintf(disk->devfs_name, DRV_NAME "/%u_%u", host->id, i); disk->major = host->major; disk->first_minor = i * CARM_MINORS_PER_MAJOR; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/cdrom/cdrom.c linux-2.6.9/drivers/cdrom/cdrom.c --- linux.vanilla-2.6.9/drivers/cdrom/cdrom.c 2004-10-20 23:16:44.000000000 +0100 +++ linux-2.6.9/drivers/cdrom/cdrom.c 2004-12-07 17:50:37.796391288 +0000 @@ -540,6 +540,8 @@ return ret; mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; + if (be16_to_cpu(mfd->feature_code) != CDF_MRW) + return 1; *write = mfd->write; if ((ret = cdrom_mrw_probe_pc(cdi))) { @@ -1046,7 +1048,8 @@ This ensures that the drive gets unlocked after a mount fails. This is a goto to avoid bloating the driver with redundant code. */ clean_up_and_return: - cdinfo(CD_WARNING, "open failed.\n"); + /* Don't log this, its a perfectly normal user occurence */ + /* cdinfo(CD_WARNING, "open failed.\n"); */ if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 0); cdinfo(CD_OPEN, "door unlocked.\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/cdrom/cdu31a.c linux-2.6.9/drivers/cdrom/cdu31a.c --- linux.vanilla-2.6.9/drivers/cdrom/cdu31a.c 2004-10-20 23:16:44.000000000 +0100 +++ linux-2.6.9/drivers/cdrom/cdu31a.c 2004-11-08 17:17:18.000000000 +0000 @@ -65,14 +65,6 @@ * This section describes features beyond the normal audio and CD-ROM * functions of the drive. * - * 2048 byte buffer mode - * - * If a disk is mounted with -o block=2048, data is copied straight - * from the drive data port to the buffer. Otherwise, the readahead - * buffer must be involved to hold the other 1K of data when a 1K - * block operation is done. Note that with 2048 byte blocks you - * cannot execute files from the CD. - * * XA compatibility * * The driver should support XA disks for both the CDU31A and CDU33A. @@ -147,6 +139,13 @@ * Removed init_module & cleanup_module in favor of * module_init & module_exit. * Torben Mathiasen + * + * 22 October 2004 -- Make the driver work in 2.6.X + * Added workaround to fix hard lockups on eject + * Fixed door locking problem after mounting empty drive + * Set double-speed drives to double speed by default + * Removed all readahead things - not needed anymore + * Ondrej Zary */ #include @@ -179,10 +178,9 @@ #define MAJOR_NR CDU31A_CDROM_MAJOR #include -#define CDU31A_READAHEAD 4 /* 128 sector, 64kB, 32 reads read-ahead */ #define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10 -#define DEBUG 0 +#define DEBUG 1 /* Define the following if you have data corruption problems. */ #undef SONY_POLL_EACH_BYTE @@ -279,7 +277,6 @@ NULL if none. */ static int is_double_speed = 0; /* does the drive support double speed ? */ -static int is_a_cdu31a = 1; /* Is the drive a CDU31A? */ static int is_auto_eject = 1; /* Door has been locked? 1=No/0=Yes */ @@ -314,12 +311,8 @@ it will be cleared. */ static char disk_changed; -/* Variable for using the readahead buffer. The readahead buffer - is used for raw sector reads and for blocksizes that are smaller - than 2048 bytes. */ -static char readahead_buffer[CD_FRAMESIZE_RAW]; -static int readahead_dataleft = 0; -static int readahead_bad = 0; +/* This was readahead_buffer once... Now it's used only for audio reads */ +static char audio_buffer[CD_FRAMESIZE_RAW]; /* Used to time a short period to abort an operation after the drive has been idle for a while. This keeps the light on @@ -440,7 +433,6 @@ static inline void reset_drive(void) { curr_control_reg = 0; - readahead_dataleft = 0; sony_toc_read = 0; outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg); } @@ -556,82 +548,47 @@ static unsigned char errbuf[80]; switch (err_code) { - case 0x10: - return "illegal command "; - case 0x11: - return "illegal parameter "; - - case 0x20: - return "not loaded "; - case 0x21: - return "no disc "; - case 0x22: - return "not spinning "; - case 0x23: - return "spinning "; - case 0x25: - return "spindle servo "; - case 0x26: - return "focus servo "; - case 0x29: - return "eject mechanism "; - case 0x2a: - return "audio playing "; - case 0x2c: - return "emergency eject "; - - case 0x30: - return "focus "; - case 0x31: - return "frame sync "; - case 0x32: - return "subcode address "; - case 0x33: - return "block sync "; - case 0x34: - return "header address "; - - case 0x40: - return "illegal track read "; - case 0x41: - return "mode 0 read "; - case 0x42: - return "illegal mode read "; - case 0x43: - return "illegal block size read "; - case 0x44: - return "mode read "; - case 0x45: - return "form read "; - case 0x46: - return "leadout read "; - case 0x47: - return "buffer overrun "; - - case 0x53: - return "unrecoverable CIRC "; - case 0x57: - return "unrecoverable LECC "; - - case 0x60: - return "no TOC "; - case 0x61: - return "invalid subcode data "; - case 0x63: - return "focus on TOC read "; - case 0x64: - return "frame sync on TOC read "; - case 0x65: - return "TOC data "; - - case 0x70: - return "hardware failure "; - case 0x91: - return "leadin "; - case 0x92: - return "leadout "; - case 0x93: - return "data track "; + case 0x10: return "illegal command "; + case 0x11: return "illegal parameter "; + + case 0x20: return "not loaded "; + case 0x21: return "no disc "; + case 0x22: return "not spinning "; + case 0x23: return "spinning "; + case 0x25: return "spindle servo "; + case 0x26: return "focus servo "; + case 0x29: return "eject mechanism "; + case 0x2a: return "audio playing "; + case 0x2c: return "emergency eject "; + + case 0x30: return "focus "; + case 0x31: return "frame sync "; + case 0x32: return "subcode address "; + case 0x33: return "block sync "; + case 0x34: return "header address "; + + case 0x40: return "illegal track read "; + case 0x41: return "mode 0 read "; + case 0x42: return "illegal mode read "; + case 0x43: return "illegal block size read "; + case 0x44: return "mode read "; + case 0x45: return "form read "; + case 0x46: return "leadout read "; + case 0x47: return "buffer overrun "; + + case 0x53: return "unrecoverable CIRC "; + case 0x57: return "unrecoverable LECC "; + + case 0x60: return "no TOC "; + case 0x61: return "invalid subcode data "; + case 0x63: return "focus on TOC read "; + case 0x64: return "frame sync on TOC read "; + case 0x65: return "TOC data "; + + case 0x70: return "hardware failure "; + case 0x91: return "leadin "; + case 0x92: return "leadout "; + case 0x93: return "data track "; } sprintf(errbuf, "unknown 0x%02x ", err_code); return errbuf; @@ -696,8 +653,7 @@ */ static int scd_lock_door(struct cdrom_device_info *cdi, int lock) { - if (lock == 0 && sony_usage == 1) { - /* Unlock the door, only if nobody is using the drive */ + if (lock == 0) { is_auto_eject = 1; } else { is_auto_eject = 0; @@ -1143,10 +1099,9 @@ operation if the requested sector is not the next one from the drive. */ static int -start_request(unsigned int sector, unsigned int nsect, int read_nsect_only) +start_request(unsigned int sector, unsigned int nsect) { unsigned char params[6]; - unsigned int read_size; unsigned long retry_count; @@ -1154,22 +1109,7 @@ printk("Entering start_request\n"); #endif log_to_msf(sector, params); - /* If requested, read exactly what was asked. */ - if (read_nsect_only) { - read_size = nsect; - } - /* - * If the full read-ahead would go beyond the end of the media, trim - * it back to read just till the end of the media. - */ - else if ((sector + nsect) >= sony_toc.lead_out_start_lba) { - read_size = sony_toc.lead_out_start_lba - sector; - } - /* Read the full readahead amount. */ - else { - read_size = CDU31A_READAHEAD / 4; - } - size_to_buf(read_size, ¶ms[3]); + size_to_buf(nsect, ¶ms[3]); /* * Clear any outstanding attentions and wait for the drive to @@ -1198,10 +1138,8 @@ write_params(params, 6); write_cmd(SONY_READ_BLKERR_STAT_CMD); - sony_blocks_left = read_size * 4; + sony_blocks_left = nsect * 4; sony_next_block = sector * 4; - readahead_dataleft = 0; - readahead_bad = 0; #if DEBUG printk("Leaving start_request at %d\n", __LINE__); #endif @@ -1212,8 +1150,7 @@ #endif } -/* Abort a pending read operation. Clear all the drive status and - readahead variables. */ +/* Abort a pending read operation. Clear all the drive status variables. */ static void abort_read(void) { unsigned char result_reg[2]; @@ -1238,8 +1175,6 @@ } sony_blocks_left = 0; - readahead_dataleft = 0; - readahead_bad = 0; } /* Called when the timer times out. This will abort the @@ -1264,8 +1199,6 @@ write_cmd(SONY_ABORT_CMD); sony_blocks_left = 0; - readahead_dataleft = 0; - readahead_bad = 0; abort_read_started = 1; } restore_flags(flags); @@ -1274,60 +1207,30 @@ #endif } -/* Actually get data and status from the drive. */ +/* Actually get one sector of data from the drive. */ static void -input_data(char *buffer, - unsigned int bytesleft, - unsigned int nblocks, unsigned int offset, unsigned int skip) +input_data_sector(char *buffer) { - int i; - volatile unsigned char val; - - #if DEBUG - printk("Entering input_data\n"); + printk("Entering input_data_sector\n"); #endif + /* If an XA disk on a CDU31A, skip the first 12 bytes of data from - the disk. The real data is after that. */ - if (sony_xa_mode) { - for (i = 0; i < CD_XA_HEAD; i++) { - val = read_data_register(); - } - } + the disk. The real data is after that. We can use audio_buffer. */ + if (sony_xa_mode) + insb(sony_cd_read_reg, audio_buffer, CD_XA_HEAD); clear_data_ready(); - if (bytesleft == 2048) { /* 2048 byte direct buffer transfer */ - insb(sony_cd_read_reg, buffer, 2048); - readahead_dataleft = 0; - } else { - /* If the input read did not align with the beginning of the block, - skip the necessary bytes. */ - if (skip != 0) { - insb(sony_cd_read_reg, readahead_buffer, skip); - } - - /* Get the data into the buffer. */ - insb(sony_cd_read_reg, &buffer[offset], bytesleft); - - /* Get the rest of the data into the readahead buffer at the - proper location. */ - readahead_dataleft = (2048 - skip) - bytesleft; - insb(sony_cd_read_reg, - readahead_buffer + bytesleft, readahead_dataleft); - } - sony_blocks_left -= nblocks; - sony_next_block += nblocks; + insb(sony_cd_read_reg, buffer, 2048); /* If an XA disk, we have to clear out the rest of the unused - error correction data. */ - if (sony_xa_mode) { - for (i = 0; i < CD_XA_TAIL; i++) { - val = read_data_register(); - } - } + error correction data. We can use audio_buffer for that. */ + if (sony_xa_mode) + insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL); + #if DEBUG - printk("Leaving input_data at %d\n", __LINE__); + printk("Leaving input_data_sector\n"); #endif } @@ -1339,10 +1242,6 @@ unsigned char res_reg[], int *res_size) { unsigned long retry_count; - unsigned int bytesleft; - unsigned int offset; - unsigned int skip; - #if DEBUG printk("Entering read_data_block\n"); @@ -1351,67 +1250,6 @@ res_reg[0] = 0; res_reg[1] = 0; *res_size = 0; - bytesleft = nblocks * 512; - offset = 0; - - /* If the data in the read-ahead does not match the block offset, - then fix things up. */ - if (((block % 4) * 512) != ((2048 - readahead_dataleft) % 2048)) { - sony_next_block += block % 4; - sony_blocks_left -= block % 4; - skip = (block % 4) * 512; - } else { - skip = 0; - } - - /* We have readahead data in the buffer, get that first before we - decide if a read is necessary. */ - if (readahead_dataleft != 0) { - if (bytesleft > readahead_dataleft) { - /* The readahead will not fill the requested buffer, but - get the data out of the readahead into the buffer. */ - memcpy(buffer, - readahead_buffer + (2048 - - readahead_dataleft), - readahead_dataleft); - bytesleft -= readahead_dataleft; - offset += readahead_dataleft; - readahead_dataleft = 0; - } else { - /* The readahead will fill the whole buffer, get the data - and return. */ - memcpy(buffer, - readahead_buffer + (2048 - - readahead_dataleft), - bytesleft); - readahead_dataleft -= bytesleft; - bytesleft = 0; - sony_blocks_left -= nblocks; - sony_next_block += nblocks; - - /* If the data in the readahead is bad, return an error so the - driver will abort the buffer. */ - if (readahead_bad) { - res_reg[0] = 0x20; - res_reg[1] = SONY_BAD_DATA_ERR; - *res_size = 2; - } - - if (readahead_dataleft == 0) { - readahead_bad = 0; - } - - /* Final transfer is done for read command, get final result. */ - if (sony_blocks_left == 0) { - get_result(res_reg, res_size); - } -#if DEBUG - printk("Leaving read_data_block at %d\n", - __LINE__); -#endif - return; - } - } /* Wait for the drive to tell us we have something */ retry_count = jiffies + SONY_JIFFIES_TIMEOUT; @@ -1442,7 +1280,9 @@ abort_read(); } } else { - input_data(buffer, bytesleft, nblocks, offset, skip); + input_data_sector(buffer); + sony_blocks_left -= nblocks; + sony_next_block += nblocks; /* Wait for the status from the drive. */ retry_count = jiffies + SONY_JIFFIES_TIMEOUT; @@ -1473,16 +1313,7 @@ SONY_NO_LECC_ERR_BLK_STAT) || (res_reg[0] == SONY_RECOV_LECC_ERR_BLK_STAT)) { - /* The data was successful, but if data was read from - the readahead and it was bad, set the whole - buffer as bad. */ - if (readahead_bad) { - readahead_bad = 0; - res_reg[0] = 0x20; - res_reg[1] = - SONY_BAD_DATA_ERR; - *res_size = 2; - } + /* nothing here */ } else { printk ("CDU31A: Data block error: 0x%x\n", @@ -1490,12 +1321,6 @@ res_reg[0] = 0x20; res_reg[1] = SONY_BAD_DATA_ERR; *res_size = 2; - - /* Data is in the readahead buffer but an error was returned. - Make sure future requests don't use the data. */ - if (bytesleft != 2048) { - readahead_bad = 1; - } } /* Final transfer is done for read command, get final result. */ @@ -1531,11 +1356,9 @@ static void do_cdu31a_request(request_queue_t * q) { struct request *req; - int block; - int nblock; + int block, nblock, num_retries; unsigned char res_reg[12]; unsigned int res_size; - int num_retries; unsigned long flags; @@ -1591,7 +1414,10 @@ block = req->sector; nblock = req->nr_sectors; - +#if DEBUG + printk("CDU31A: request at block %d, length %d blocks\n", + block, nblock); +#endif if (!sony_toc_read) { printk("CDU31A: TOC not read\n"); end_request(req, 0); @@ -1611,17 +1437,14 @@ * If the block address is invalid or the request goes beyond the end of * the media, return an error. */ - if ((block / 4) >= sony_toc.lead_out_start_lba) { - printk("CDU31A: Request past end of media\n"); - end_request(req, 0); - continue; - } if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) { printk("CDU31A: Request past end of media\n"); end_request(req, 0); continue; } + if (nblock > 4) + nblock = 4; num_retries = 0; try_read_again: @@ -1636,7 +1459,7 @@ /* If no data is left to be read from the drive, start the next request. */ if (sony_blocks_left == 0) { - if (start_request(block / 4, CDU31A_READAHEAD / 4, 0)) { + if (start_request(block / 4, nblock / 4)) { end_request(req, 0); continue; } @@ -1655,7 +1478,7 @@ end_request(req, 0); continue; } - if (start_request(block / 4, CDU31A_READAHEAD / 4, 0)) { + if (start_request(block / 4, nblock / 4)) { printk("CDU31a: start request failed\n"); end_request(req, 0); continue; @@ -1665,7 +1488,12 @@ read_data_block(req->buffer, block, nblock, res_reg, &res_size); if (res_reg[0] != 0x20) { - end_request(req, 1); + if (!end_that_request_first(req, 1, nblock)) { + spin_lock_irq(q->queue_lock); + blkdev_dequeue_request(req); + end_that_request_last(req); + spin_unlock_irq(q->queue_lock); + } continue; } @@ -1774,7 +1602,7 @@ /* This seems to slow things down enough to make it work. This * appears to be a problem in do_sony_cd_cmd. This printk seems * to address the symptoms... -Erik */ -#if 1 +#if DEBUG printk("cdu31a: Trying session %d\n", session); #endif parms[0] = session; @@ -2529,8 +2357,7 @@ return. */ retval = 0; - /* start_request clears out any readahead data, so it should be safe. */ - if (start_request(ra->addr.lba, ra->nframes, 1)) { + if (start_request(ra->addr.lba, ra->nframes)) { retval = -EIO; goto exit_read_audio; } @@ -2538,7 +2365,7 @@ /* For every requested frame. */ cframe = 0; while (cframe < ra->nframes) { - read_audio_data(readahead_buffer, res_reg, &res_size); + read_audio_data(audio_buffer, res_reg, &res_size); if ((res_reg[0] & 0xf0) == 0x20) { if (res_reg[1] == SONY_BAD_DATA_ERR) { printk @@ -2567,7 +2394,7 @@ /* Restart the request on the current frame. */ if (start_request (ra->addr.lba + cframe, - ra->nframes - cframe, 1)) { + ra->nframes - cframe)) { retval = -EIO; goto exit_read_audio; } @@ -2575,7 +2402,7 @@ /* Don't go back to the top because don't want to get into and infinite loop. A lot of code gets duplicated, but that's no big deal, I don't guess. */ - read_audio_data(readahead_buffer, res_reg, + read_audio_data(audio_buffer, res_reg, &res_size); if ((res_reg[0] & 0xf0) == 0x20) { if (res_reg[1] == @@ -2596,7 +2423,7 @@ } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe), - readahead_buffer, + audio_buffer, CD_FRAMESIZE_RAW)) { retval = -EFAULT; goto exit_read_audio; @@ -2610,7 +2437,7 @@ goto exit_read_audio; } } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe), - (char *)readahead_buffer, + (char *)audio_buffer, CD_FRAMESIZE_RAW)) { retval = -EFAULT; goto exit_read_audio; @@ -3061,12 +2888,18 @@ * Open the drive for operations. Spin the drive up and read the table of * contents if these have not already been done. */ -static int scd_open(struct cdrom_device_info *cdi, int openmode) +static int scd_open(struct cdrom_device_info *cdi, int purpose) { unsigned char res_reg[12]; unsigned int res_size; unsigned char params[2]; + if (purpose == 1) { + /* Open for IOCTLs only - no media check */ + sony_usage++; + return 0; + } + if (sony_usage == 0) { if (scd_spinup() != 0) return -EIO; @@ -3151,8 +2984,7 @@ .dev_ioctl = scd_dev_ioctl, .capability = CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_MULTI_SESSION | - CDC_MULTI_SESSION | CDC_MCN | - CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | + CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, .n_minors = 1, }; @@ -3177,7 +3009,19 @@ static int scd_block_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg) { - return cdrom_ioctl(file, &scd_info, inode, cmd, arg); + /* The eject and close commands should be handled by Uniform CD-ROM + * driver - but I always got hard lockup instead of eject + * until I put this here. + */ + switch (cmd) { + case CDROMEJECT: + scd_lock_door(&scd_info, 0); + return scd_tray_move(&scd_info, 1); + case CDROMCLOSETRAY: + return scd_tray_move(&scd_info, 0); + default: + return cdrom_ioctl(file, &scd_info, inode, cmd, arg); + } } static int scd_block_media_changed(struct gendisk *disk) @@ -3372,6 +3216,7 @@ tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */ cdu31a_irq = 0; + sony_speed = is_double_speed; /* Set 2X drives to 2X by default */ set_drive_params(sony_speed); cdu31a_irq = tmp_irq; @@ -3417,13 +3262,12 @@ strcat(msg, buf); } strcat(msg, "\n"); - - is_a_cdu31a = - strcmp("CD-ROM CDU31A", drive_config.product_id) == 0; - + printk("%s",msg); + cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock); if (!cdu31a_queue) goto errout0; + blk_queue_hardsect_size(cdu31a_queue, 2048); init_timer(&cdu31a_abort_timer); cdu31a_abort_timer.function = handle_abort_timeout; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/cdrom/cdu31a.h linux-2.6.9/drivers/cdrom/cdu31a.h --- linux.vanilla-2.6.9/drivers/cdrom/cdu31a.h 2004-10-20 22:33:11.000000000 +0100 +++ linux-2.6.9/drivers/cdrom/cdu31a.h 2004-11-08 17:17:18.000000000 +0000 @@ -72,10 +72,10 @@ from drive (in 1/100th's of seconds). */ -#define SONY_JIFFIES_TIMEOUT 1000 /* Maximum number of times the +#define SONY_JIFFIES_TIMEOUT (10*HZ) /* Maximum number of times the drive will wait/try for an operation */ -#define SONY_RESET_TIMEOUT 100 /* Maximum number of times the +#define SONY_RESET_TIMEOUT HZ /* Maximum number of times the drive will wait/try a reset operation */ #define SONY_READY_RETRIES 20000 /* How many times to retry a diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/agp/ali-agp.c linux-2.6.9/drivers/char/agp/ali-agp.c --- linux.vanilla-2.6.9/drivers/char/agp/ali-agp.c 2004-10-20 22:32:27.000000000 +0100 +++ linux-2.6.9/drivers/char/agp/ali-agp.c 2004-11-19 17:03:42.000000000 +0000 @@ -277,6 +277,14 @@ .device_id = PCI_DEVICE_ID_AL_M1671, .chipset_name = "M1671", }, + { + .device_id = PCI_DEVICE_ID_AL_M1681, + .chipset_name = "M1681", + }, + { + .device_id = PCI_DEVICE_ID_AL_M1683, + .chipset_name = "M1683", + }, { }, /* dummy final entry, always present */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/agp/amd64-agp.c linux-2.6.9/drivers/char/agp/amd64-agp.c --- linux.vanilla-2.6.9/drivers/char/agp/amd64-agp.c 2004-10-20 23:16:45.000000000 +0100 +++ linux-2.6.9/drivers/char/agp/amd64-agp.c 2004-11-19 17:05:52.000000000 +0000 @@ -46,6 +46,11 @@ #define NVIDIA_X86_64_1_APBASE2 0xd8 #define NVIDIA_X86_64_1_APLIMIT2 0xdc +/* ULi K8 registers */ +#define ULI_X86_64_BASE_ADDR 0x10 +#define ULI_X86_64_HTT_FEA_REG 0x50 +#define ULI_X86_64_ENU_SCR_REG 0x54 + static int nr_garts; static struct pci_dev * hammers[MAX_HAMMER_GARTS]; @@ -405,6 +410,62 @@ } } + +static struct aper_size_info_32 uli_sizes[7] = +{ + {256, 65536, 6, 10}, + {128, 32768, 5, 9}, + {64, 16384, 4, 8}, + {32, 8192, 3, 7}, + {16, 4096, 2, 6}, + {8, 2048, 1, 4}, + {4, 1024, 0, 3} +}; + +static int __devinit uli_agp_init(struct pci_dev *pdev) +{ + u32 httfea,baseaddr,enuscr; + struct pci_dev *dev1; + int i; + unsigned size = amd64_fetch_size(); + printk(KERN_INFO PFX "Setting up ULi AGP. \n"); + dev1 = pci_find_slot ((unsigned int)pdev->bus->number,PCI_DEVFN(0,0)); + if (dev1 == NULL) { + printk(KERN_INFO PFX "agpgart: Detected a ULi chipset, " + "but could not fine the secondary device.\n"); + return -ENODEV; + } + for (i = 0; i < ARRAY_SIZE(uli_sizes); i++) + if (uli_sizes[i].size == size) + break; + + if (i == ARRAY_SIZE(uli_sizes)) { + printk(KERN_INFO PFX "No ULi size found for %d\n", size); + return -ENODEV; + } + + + /* shadow x86-64 registers into ULi registers */ + pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &httfea); + + /* if x86-64 aperture base is beyond 4G, exit here */ + if ( (httfea & 0x7fff) >> (32 - 25) ) + return -ENODEV; + + httfea = (httfea& 0x7fff) << 25; + + pci_read_config_dword(pdev, ULI_X86_64_BASE_ADDR, &baseaddr); + baseaddr&= ~PCI_BASE_ADDRESS_MEM_MASK; + baseaddr|= httfea; + pci_write_config_dword(pdev, ULI_X86_64_BASE_ADDR, baseaddr); + + enuscr= httfea+ (size * 1024 * 1024) - 1; + pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea); + pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr); + return 0; +} + + static struct aper_size_info_32 nforce3_sizes[5] = { {512, 131072, 7, 0x00000000 }, @@ -513,6 +574,14 @@ } } + if (pdev->vendor == PCI_VENDOR_ID_AL) { + int ret = uli_agp_init(pdev); + if (ret) { + agp_put_bridge(bridge); + return ret; + } + } + pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); } @@ -536,6 +605,15 @@ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + /* ULi M1689 */ + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_AL, + .device = PCI_DEVICE_ID_AL_M1689, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, /* VIA K8T800Pro */ { .class = (PCI_CLASS_BRIDGE_HOST << 8), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/agp/ati-agp.c linux-2.6.9/drivers/char/agp/ati-agp.c --- linux.vanilla-2.6.9/drivers/char/agp/ati-agp.c 2004-10-20 23:16:45.000000000 +0100 +++ linux-2.6.9/drivers/char/agp/ati-agp.c 2004-12-10 23:41:28.000000000 +0000 @@ -62,6 +62,7 @@ SetPageReserved(virt_to_page(page_map->real)); err = map_page_into_agp(virt_to_page(page_map->real)); + /* AUDIT?: Needs to flush TLB */ /* CACHE_FLUSH(); */ global_cache_flush(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), @@ -85,6 +86,7 @@ static void ati_free_page_map(ati_page_map *page_map) { unmap_page_from_agp(virt_to_page(page_map->real)); + /* AUDIT?: Needs to flush TLB */ iounmap(page_map->remapped); ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/agp/generic.c linux-2.6.9/drivers/char/agp/generic.c --- linux.vanilla-2.6.9/drivers/char/agp/generic.c 2004-10-20 23:16:45.000000000 +0100 +++ linux-2.6.9/drivers/char/agp/generic.c 2004-12-10 23:39:50.000000000 +0000 @@ -857,6 +857,8 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), agp_bridge->gatt_table+j); + /* AUDIT?: Posting */ + /* AUDIT?: CPU cache flush missing */ agp_bridge->driver->tlb_flush(mem); return 0; } @@ -876,6 +878,8 @@ for (i = pg_start; i < (mem->page_count + pg_start); i++) writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i); + /* AUDIT?: Posting */ + /* AUDIT?: CPU cache flush missing */ agp_bridge->driver->tlb_flush(mem); return 0; } @@ -916,6 +920,8 @@ return NULL; map_page_into_agp(page); + + /* AUDIT? Must call global_tlb_flush */ get_page(page); SetPageLocked(page); @@ -934,6 +940,9 @@ page = virt_to_page(addr); unmap_page_from_agp(page); + + /* AUDIT? Must call global_tlb_flush */ + put_page(page); unlock_page(page); free_page((unsigned long)addr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/agp/intel-agp.c linux-2.6.9/drivers/char/agp/intel-agp.c --- linux.vanilla-2.6.9/drivers/char/agp/intel-agp.c 2004-10-20 23:16:45.000000000 +0100 +++ linux-2.6.9/drivers/char/agp/intel-agp.c 2004-12-10 23:36:23.000000000 +0000 @@ -136,6 +136,7 @@ agp_bridge->scratch_page); } } + /* AUDIT?: posted */ return 0; } @@ -168,6 +169,7 @@ __free_page(page); return NULL; } + /* AUDIT? Must call global_flush_tlb but does not */ get_page(page); SetPageLocked(page); atomic_inc(&agp_bridge->current_memory_agp); @@ -182,6 +184,7 @@ return; page = virt_to_page(addr); + /* AUDIT? Must call global_flush_tlb but does not */ change_page_attr(page, 4, PAGE_KERNEL); put_page(page); unlock_page(page); @@ -232,6 +235,7 @@ I810_PTE_BASE + (j * 4), agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); } + /* AUDIT? Posting */ global_cache_flush(); agp_bridge->driver->tlb_flush(mem); @@ -248,7 +252,7 @@ I810_PTE_BASE + (i * 4), agp_bridge->scratch_page); } - + /* AUDIT? Posting */ global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; @@ -539,6 +543,8 @@ for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); + /* AUDIT? GART tlb not flushed ? */ + /* AUDIT? Posting */ return (0); } @@ -581,6 +587,7 @@ OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + /* AUDIT? Posting */ global_cache_flush(); agp_bridge->driver->tlb_flush(mem); @@ -603,6 +610,7 @@ for (i = pg_start; i < (mem->page_count + pg_start); i++) OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); + /* AUDIT? Posting */ global_cache_flush(); agp_bridge->driver->tlb_flush(mem); @@ -643,7 +651,7 @@ for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) OUTREG32(intel_i830_private.gtt, i, agp_bridge->scratch_page); } - + /* AUDIT? Posting, gart tlb not flushed */ return (0); } @@ -686,6 +694,7 @@ 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)); + /* AUDIT? Posting */ global_cache_flush(); agp_bridge->driver->tlb_flush(mem); @@ -708,6 +717,7 @@ for (i = pg_start; i < (mem->page_count + pg_start); i++) OUTREG32(intel_i830_private.gtt, i, agp_bridge->scratch_page); + /* AUDIT? Posting */ global_cache_flush(); agp_bridge->driver->tlb_flush(mem); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/moxa.c linux-2.6.9/drivers/char/moxa.c --- linux.vanilla-2.6.9/drivers/char/moxa.c 2004-10-20 23:16:52.000000000 +0100 +++ linux-2.6.9/drivers/char/moxa.c 2004-10-16 22:36:39.000000000 +0100 @@ -694,7 +694,6 @@ return; MoxaPortFlushData(ch->port, 1); tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); } static int moxa_chars_in_buffer(struct tty_struct *tty) @@ -953,7 +952,6 @@ if (!tp->stopped) { ch->statusflags &= ~LOWWAIT; tty_wakeup(tp); - wake_up_interruptible(&tp->write_wait); } } } @@ -1120,7 +1118,6 @@ if (MoxaPortTxQueue(ch->port) == 0) { ch->statusflags &= ~EMPTYWAIT; tty_wakeup(ch->tty); - wake_up_interruptible(&ch->tty->write_wait); return; } moxaEmptyTimer[ch->port].expires = jiffies + HZ; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/tty_io.c linux-2.6.9/drivers/char/tty_io.c --- linux.vanilla-2.6.9/drivers/char/tty_io.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/char/tty_io.c 2004-10-28 00:47:53.000000000 +0100 @@ -1981,10 +1981,10 @@ static int tioccons(struct file *file) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; if (file->f_op->write == redirected_tty_write) { struct file *f; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; spin_lock(&redirect_lock); f = redirect; redirect = NULL; @@ -2117,11 +2117,11 @@ static int send_break(struct tty_struct *tty, int duration) { - set_current_state(TASK_INTERRUPTIBLE); - tty->driver->break_ctl(tty, -1); - if (!signal_pending(current)) + if (!signal_pending(current)) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(duration); + } tty->driver->break_ctl(tty, 0); if (signal_pending(current)) return -EINTR; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/watchdog/alim7101_wdt.c linux-2.6.9/drivers/char/watchdog/alim7101_wdt.c --- linux.vanilla-2.6.9/drivers/char/watchdog/alim7101_wdt.c 2004-10-20 22:32:28.000000000 +0100 +++ linux-2.6.9/drivers/char/watchdog/alim7101_wdt.c 2004-12-11 00:05:17.000000000 +0000 @@ -12,6 +12,11 @@ * because this particular WDT has a very short timeout (1.6 * seconds) and it would be insane to count on any userspace * daemon always getting scheduled within that time frame. + * + * Additions: + * Aug 23, 2004 - Added use_gpio module parameter for use on revision a1d PMUs + * found on very old cobalt hardware. + * -- Mike Waychison */ #include @@ -38,6 +43,8 @@ #define WDT_DISABLE 0x8C #define ALI_7101_WDT 0x92 +#define ALI_7101_GPIO 0x7D +#define ALI_7101_GPIO_O 0x7E #define ALI_WDT_ARM 0x01 /* @@ -57,6 +64,10 @@ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); +static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */ +module_param(use_gpio, int, 0); +MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)"); + static void wdt_timer_ping(unsigned long); static struct timer_list timer; static unsigned long next_heartbeat; @@ -90,6 +101,13 @@ pci_read_config_byte(alim7101_pmu, 0x92, &tmp); pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp + | 0x20); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp + & ~0x20); + } } else { printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } @@ -106,11 +124,21 @@ { char tmp; - pci_read_config_byte(alim7101_pmu, 0x92, &tmp); - if (writeval == WDT_ENABLE) + pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp); + if (writeval == WDT_ENABLE) { pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); - else + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20); + } + + } else { pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20); + } + } } static void wdt_startup(void) @@ -334,7 +362,13 @@ return -EBUSY; } pci_read_config_byte(ali1543_south, 0x5e, &tmp); - if ((tmp & 0x1e) != 0x12) { + if ((tmp & 0x1e) == 0x00) { + if (!use_gpio) { + printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); + return -EBUSY; + } + nowayout = 1; + } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); return -EBUSY; } @@ -364,6 +398,10 @@ goto err_out_miscdev; } + if (nowayout) { + __module_get(THIS_MODULE); + } + printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n", timeout, nowayout); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/watchdog/i8xx_tco.c linux-2.6.9/drivers/char/watchdog/i8xx_tco.c --- linux.vanilla-2.6.9/drivers/char/watchdog/i8xx_tco.c 2004-10-20 22:32:28.000000000 +0100 +++ linux-2.6.9/drivers/char/watchdog/i8xx_tco.c 2004-10-21 22:39:49.000000000 +0100 @@ -465,7 +465,7 @@ goto unreg_notifier; } - tco_timer_keepalive (); + tco_timer_stop (); printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n", TCOBASE, heartbeat, nowayout); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/firmware/edd.c linux-2.6.9/drivers/firmware/edd.c --- linux.vanilla-2.6.9/drivers/firmware/edd.c 2004-10-20 22:33:05.000000000 +0100 +++ linux-2.6.9/drivers/firmware/edd.c 2004-11-15 16:01:57.000000000 +0000 @@ -70,7 +70,7 @@ static int edd_dev_is_type(struct edd_device *edev, const char *type); static struct pci_dev *edd_get_pci_dev(struct edd_device *edev); -static struct edd_device *edd_devices[EDDMAXNR]; +static struct edd_device *edd_devices[EDD_MBR_SIG_MAX]; #define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \ struct edd_attribute edd_attr_##_name = { \ @@ -728,9 +728,9 @@ static inline int edd_num_devices(void) { - return min_t(unsigned char, - max_t(unsigned char, edd.edd_info_nr, edd.mbr_signature_nr), - max_t(unsigned char, EDD_MBR_SIG_MAX, EDDMAXNR)); + return max_t(unsigned char, + min_t(unsigned char, EDD_MBR_SIG_MAX, edd.mbr_signature_nr), + min_t(unsigned char, EDDMAXNR, edd.edd_info_nr)); } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide.c linux-2.6.9/drivers/ide/ide.c --- linux.vanilla-2.6.9/drivers/ide/ide.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide.c 2004-11-30 20:18:50.000000000 +0000 @@ -175,6 +175,7 @@ static int initializing; /* set while initializing built-in drivers */ DECLARE_MUTEX(ide_cfg_sem); +EXPORT_SYMBOL_GPL(ide_cfg_sem); spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; #ifdef CONFIG_BLK_DEV_IDEPCI @@ -205,11 +206,13 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index) { unsigned int unit; + unsigned int key = hwif->key; /* bulk initialize hwif & drive info with zeros */ memset(hwif, 0, sizeof(ide_hwif_t)); /* fill in any non-zero initial values */ + hwif->key = key + 1; /* Protected by ide_cfg_sem */ hwif->index = index; hwif->major = ide_hwif_to_major[index]; @@ -320,6 +323,92 @@ #endif } +/* + * ide_drive_from_key - turn key into drive + * @kval: persistent key + * + * Convert a key into a drive. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +ide_drive_t *ide_drive_from_key(void *kval) +{ + unsigned long key = (unsigned long) kval; + int idx = (key >> 8) & 0xFF; + int drive = key & 3; + ide_hwif_t *hwif = &ide_hwifs[idx]; + ide_drive_t *ret; + + key >>= 16; + + if(hwif->configured == 0 || hwif->present == 0 || hwif->drives[drive].dead || hwif->key != key) + ret = NULL; + else + ret = &ide_hwifs[idx].drives[drive]; + + return ret; +} + +EXPORT_SYMBOL_GPL(ide_drive_from_key); + +/* + * ide_drive_to_key - turn drive to persistent key + * @drive: drive to use + * + * Convert drive into a key. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +void *ide_drive_to_key(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long val; + + val = (hwif->index << 8) | (hwif->key << 16) | drive->select.b.unit; + return (void *)val; +} + +/* + * ide_hwif_from_key - turn key into hwif + * @kval: persistent key + * + * Convert a key into a drive. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +ide_hwif_t *ide_hwif_from_key(void *kval) +{ + unsigned long key = (unsigned long) kval; + int idx = (key >> 8) & 0xFF; + ide_hwif_t *hwif = &ide_hwifs[idx]; + + key >>= 16; + + if(hwif->configured == 0 || hwif->present == 0 || hwif->key != key) + return NULL; + return hwif; +} + +/* + * ide_hwif_to_key - turn drive to persistent key + * @hwif: hwif to use + * + * Convert drive into a key. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +void *ide_hwif_to_key(ide_hwif_t *hwif) +{ + unsigned long val; + + val = (hwif->index << 8) | (hwif->key << 16); + return (void *)val; +} + /** * ide_system_bus_speed - guess bus speed * @@ -490,11 +579,16 @@ } /* - * drives_lock protects the list of drives, drivers_lock the - * list of drivers. Currently nobody takes both at once. + * drives_lock protects the list of drives, drivers lock the + * list of drivers. Currently nobody takes both at once. + * drivers_sem guards the drivers_list for readers that may + * sleep. It must be taken before drivers_lock. Take drivers_sem + * before ide_setting_sem and idecfg_sem before either of the + * others. */ static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_MUTEX(drivers_sem); static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(drivers); @@ -504,7 +598,7 @@ { struct list_head *p; loff_t l = *pos; - spin_lock(&drivers_lock); + down(&drivers_sem); list_for_each(p, &drivers) if (!l--) return list_entry(p, ide_driver_t, drivers); @@ -520,7 +614,7 @@ static void m_stop(struct seq_file *m, void *v) { - spin_unlock(&drivers_lock); + up(&drivers_sem); } static int show_driver(struct seq_file *m, void *v) @@ -679,6 +773,7 @@ hwif->maskproc = tmp_hwif->maskproc; hwif->quirkproc = tmp_hwif->quirkproc; hwif->busproc = tmp_hwif->busproc; + hwif->raw_taskfile = tmp_hwif->raw_taskfile; hwif->ata_input_data = tmp_hwif->ata_input_data; hwif->ata_output_data = tmp_hwif->ata_output_data; @@ -739,14 +834,16 @@ } /** - * ide_unregister - free an ide interface - * @index: index of interface (will change soon to a pointer) + * __ide_unregister_hwif - free an ide interface + * @hwif: interface to unregister * * Perform the final unregister of an IDE interface. At the moment * we don't refcount interfaces so this will also get split up. * * Locking: - * The caller must not hold the IDE locks + * The caller must not hold the IDE locks except for ide_cfg_sem + * which must be held. + * * The drive present/vanishing is not yet properly locked * Take care with the callbacks. These have been split to avoid * deadlocking the IDE layer. The shutdown callback is called @@ -756,26 +853,39 @@ * isnt yet done btw). After we commit to the final kill we * call the cleanup callback with the ide locks held. * + * An interface can be in four states we care about + * - It can be busy (drive or driver thinks its active). No unload + * - It can be unconfigured - which means its already gone + * - It can be configured and present - a full interface + * - It can be configured and not present - pci configured but no drives + * so logically absent. + * * Unregister restores the hwif structures to the default state. - * This is raving bonkers. */ -void ide_unregister(unsigned int index) +int __ide_unregister_hwif(ide_hwif_t *hwif) { - ide_drive_t *drive; - ide_hwif_t *hwif, *g; + ide_drive_t *drive = NULL; /* keep compiler happy */ + ide_hwif_t *g; static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */ ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; - - BUG_ON(index >= MAX_HWIFS); + int was_present; + int ret = 0; + int index = hwif->index; BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); - down(&ide_cfg_sem); + + /* Make sure nobody sneaks in via the proc interface */ + down(&ide_setting_sem); + + /* Now ensure nobody gets in for I/O while we clean up and + do the busy check. If busy is set then the device is still + open and we must stop */ spin_lock_irq(&ide_lock); - hwif = &ide_hwifs[index]; - if (!hwif->present) + + if (!hwif->configured) goto abort; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; @@ -785,9 +895,17 @@ goto abort; drive->dead = 1; } + /* + * Protect against new users. From this point the hwif + * is not present so cannot be opened by a new I/O source. + * This also invalidates key driven access from procfs + */ + + was_present = hwif->present; hwif->present = 0; spin_unlock_irq(&ide_lock); + up(&ide_setting_sem); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; @@ -798,28 +916,38 @@ #ifdef CONFIG_PROC_FS destroy_proc_ide_drives(hwif); + destroy_proc_ide_interface(hwif); #endif + spin_lock_irq(&ide_lock); hwgroup = hwif->hwgroup; - /* - * free the irq if we were the only hwif using it - */ - g = hwgroup->hwif; - do { - if (g->irq == hwif->irq) - ++irq_count; - g = g->next; - } while (g != hwgroup->hwif); - if (irq_count == 1) + if(hwgroup) + { + /* + * free the irq if we were the only hwif using it + */ + g = hwgroup->hwif; + do { + if (g->irq == hwif->irq) + ++irq_count; + g = g->next; + } while (g != hwgroup->hwif); + } + spin_unlock_irq(&ide_lock); + + if (irq_count == 1 && hwgroup) free_irq(hwif->irq, hwgroup); - spin_lock_irq(&ide_lock); /* * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. + * + * FIXME: should defer this I think */ - ide_hwif_release_regions(hwif); + + if(was_present) + ide_hwif_release_regions(hwif); /* * Remove us from the hwgroup, and free @@ -833,6 +961,14 @@ } if (!drive->present) continue; + + /* + * The hwgroup chain is IRQ touched. We must protect + * walking this from an IDE event for another device + * in the chain + */ + + spin_lock_irq(&ide_lock); if (drive == drive->next) { /* special case: last drive from hwgroup. */ BUG_ON(hwgroup->drive != drive); @@ -849,47 +985,67 @@ hwgroup->hwif = HWIF(hwgroup->drive); } } + spin_unlock_irq(&ide_lock); + + /* + * The rest of the cleanup is private + */ + BUG_ON(hwgroup->drive == drive); if (drive->id != NULL) { kfree(drive->id); drive->id = NULL; } drive->present = 0; - /* Messed up locking ... */ - spin_unlock_irq(&ide_lock); blk_cleanup_queue(drive->queue); device_unregister(&drive->gendev); down(&drive->gendev_rel_sem); - spin_lock_irq(&ide_lock); drive->queue = NULL; } - if (hwif->next == hwif) { - BUG_ON(hwgroup->hwif != hwif); - kfree(hwgroup); - } else { - /* There is another interface in hwgroup. - * Unlink us, and set hwgroup->drive and ->hwif to - * something sane. - */ - g = hwgroup->hwif; - while (g->next != hwif) - g = g->next; - g->next = hwif->next; - if (hwgroup->hwif == hwif) { - /* Chose a random hwif for hwgroup->hwif. - * It's guaranteed that there are no drives - * left in the hwgroup. + /* + * Lock against hwgroup walkers including interrupts off other + * IDE devices wile we unhook ourselves. + */ + + spin_lock_irq(&ide_lock); + + if (hwgroup) + { + if (hwif->next == hwif) { + BUG_ON(hwgroup->hwif != hwif); + kfree(hwgroup); + } else { + /* There is another interface in hwgroup. + * Unlink us, and set hwgroup->drive and ->hwif to + * something sane. */ - BUG_ON(hwgroup->drive != NULL); - hwgroup->hwif = g; + g = hwgroup->hwif; + while (g->next != hwif) + g = g->next; + g->next = hwif->next; + if (hwgroup->hwif == hwif) { + /* Chose a random hwif for hwgroup->hwif. + * It's guaranteed that there are no drives + * left in the hwgroup. + */ + BUG_ON(hwgroup->drive != NULL); + hwgroup->hwif = g; + } + BUG_ON(hwgroup->hwif == hwif); } - BUG_ON(hwgroup->hwif == hwif); } - - /* More messed up locking ... */ spin_unlock_irq(&ide_lock); - device_unregister(&hwif->gendev); - down(&hwif->gendev_rel_sem); + + /* + * PCI interfaces with no devices don't exist in the device + * tree so don't unregister them. + */ + + if(was_present) + { + device_unregister(&hwif->gendev); + down(&hwif->gendev_rel_sem); + } /* * Remove us from the kernel's knowledge @@ -903,6 +1059,13 @@ unregister_blkdev(hwif->major, hwif->name); spin_lock_irq(&ide_lock); + /* + * Let the driver free up private objects + */ + + if(hwif->remove) + hwif->remove(hwif); + if (hwif->dma_base) { (void) ide_release_dma(hwif); @@ -914,6 +1077,7 @@ hwif->dma_vendor3 = 0; hwif->dma_prdtable = 0; } + hwif->chipset = ide_unknown; /* copy original settings */ tmp_hwif = *hwif; @@ -922,15 +1086,58 @@ init_hwif_data(hwif, index); init_hwif_default(hwif, index); + hwif->configured = 0; + ide_hwif_restore(hwif, &tmp_hwif); + + spin_unlock_irq(&ide_lock); + return 0; abort: + if(hwif->configured) + { + printk("Unregister %d fail %d %d\n", index, drive->usage, DRIVER(drive)->busy); + ret = -EBUSY; + } + else + { + printk("No such hwif!\n"); + ret = -ENOENT; + } spin_unlock_irq(&ide_lock); - up(&ide_cfg_sem); + up(&ide_setting_sem); + return ret; } -EXPORT_SYMBOL(ide_unregister); +EXPORT_SYMBOL_GPL(__ide_unregister_hwif); +/** + * ide_unregister_hwif - free an ide interface + * @hwif: interface to unregister + * + * Perform the final unregister of an IDE interface. At the moment + * we don't refcount interfaces so this will also get split up. + * Unregister restores the hwif structures to the default state. + * + * No locks should be held on entry. When an unregister must + * be done atomically with a register see __ide_unregister_hwif + * and hold the ide_cfg_sem yourself. + */ + +int ide_unregister_hwif(ide_hwif_t *hwif) +{ + int ret; + + /* This protects two things. Firstly it serializes the + shutdown sequence, secondly it protects us from + races while we are killing off a device */ + down(&ide_cfg_sem); + ret = __ide_unregister_hwif(hwif); + up(&ide_cfg_sem); + return ret; +} + +EXPORT_SYMBOL_GPL(ide_unregister_hwif); /** * ide_setup_ports - set up IDE interface ports @@ -986,21 +1193,29 @@ } /** - * ide_register_hw - register IDE interface + * ide_register_hw_with_fixup - register IDE interface * @hw: hardware registers * @hwifp: pointer to returned hwif + * @fixup function to call * * Register an IDE interface, specifying exactly the registers etc. - * Set init=1 iff calling before probes have taken place. + * Set init=1 iff calling before probes have taken place. The + * ide_cfg_sem protects this against races. + * + * Invokes a fixup function after the probe and before device attachment + * that can be used by the driver to amend settings or to work around + * hardware funnies. * * Returns -1 on error. */ -int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp) +int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void (*fixup)(ide_hwif_t *hwif)) { int index, retry = 1; ide_hwif_t *hwif; + down(&ide_cfg_sem); + do { for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; @@ -1011,31 +1226,40 @@ hwif = &ide_hwifs[index]; if (hwif->hold) continue; - if ((!hwif->present && !hwif->mate && !initializing) || + if ((!hwif->configured && !hwif->mate && !initializing) || (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing)) goto found; } + /* FIXME- this check should die as should the retry loop */ for (index = 0; index < MAX_HWIFS; index++) - ide_unregister(index); + { + hwif = &ide_hwifs[index]; + __ide_unregister_hwif(hwif); + } } while (retry--); + + up(&ide_cfg_sem); return -1; found: - if (hwif->present) - ide_unregister(index); + /* FIXME: do we really need this case */ + if (hwif->configured) + __ide_unregister_hwif(hwif); else if (!hwif->hold) { init_hwif_data(hwif, index); init_hwif_default(hwif, index); } - if (hwif->present) + if (hwif->configured) return -1; + hwif->configured = 1; memcpy(&hwif->hw, hw, sizeof(*hw)); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); hwif->irq = hw->irq; hwif->noprobe = 0; hwif->chipset = hw->chipset; + up(&ide_cfg_sem); if (!initializing) { - probe_hwif_init(hwif); + probe_hwif_init_with_fixup(hwif, fixup); create_proc_ide_interfaces(); } @@ -1045,6 +1269,25 @@ return (initializing || hwif->present) ? index : -1; } +EXPORT_SYMBOL(ide_register_hw_with_fixup); + +/** + * ide_register_hw - register new IDE hardware + * @hw: hardware registers + * @hwifp: pointer to returned hwif + * + * Register an IDE interface, specifying exactly the registers etc. + * Set init=1 iff calling before probes have taken place. The + * ide_cfg_sem protects this against races. + * + * Returns -1 on error. + */ + +int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwif) +{ + return ide_register_hw_with_fixup(hw, hwif, NULL); +} + EXPORT_SYMBOL(ide_register_hw); /* @@ -1069,21 +1312,21 @@ * @set: setting * * Removes the setting named from the device if it is present. - * The function takes the settings_lock to protect against - * parallel changes. This function must not be called from IRQ - * context. Returns 0 on success or -1 on failure. + * This function must not be called from IRQ context. Returns 0 + * on success or -1 on failure. * * BUGS: This code is seriously over-engineered. There is also * magic about how the driver specific features are setup. If * a driver is attached we assume the driver settings are auto * remove. + * + * The caller must hold settings_lock */ int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) { ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; - down(&ide_setting_sem); while ((*p) && strcmp((*p)->name, name) < 0) p = &((*p)->next); if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL) @@ -1107,10 +1350,8 @@ if (drive->driver != &idedefault_driver) setting->auto_remove = 1; *p = setting; - up(&ide_setting_sem); return 0; abort: - up(&ide_setting_sem); if (setting) kfree(setting); return -1; @@ -1119,7 +1360,7 @@ EXPORT_SYMBOL(ide_add_setting); /** - * __ide_remove_setting - remove an ide setting option + * ide_remove_setting - remove an ide setting option * @drive: drive to use * @name: setting name * @@ -1127,7 +1368,7 @@ * The caller must hold the setting semaphore. */ -static void __ide_remove_setting (ide_drive_t *drive, char *name) +static void ide_remove_setting (ide_drive_t *drive, char *name) { ide_settings_t **p, *setting; @@ -1205,7 +1446,7 @@ setting = drive->settings; while (setting) { if (setting->auto_remove) { - __ide_remove_setting(drive, setting->name); + ide_remove_setting(drive, setting->name); goto repeat; } setting = setting->next; @@ -1404,6 +1645,7 @@ void ide_add_generic_settings (ide_drive_t *drive) { + down(&ide_setting_sem); /* * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function */ @@ -1416,6 +1658,8 @@ ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL); ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate); ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL); + + up(&ide_setting_sem); } /** @@ -1472,28 +1716,30 @@ * A return of zero indicates attachment to a driver, of one * attachment to the default driver. * - * Takes drivers_lock. + * Takes the driver list lock and the ide_settings semaphore. */ int ata_attach(ide_drive_t *drive) { struct list_head *p; - spin_lock(&drivers_lock); + down(&drivers_sem); + down(&ide_setting_sem); list_for_each(p, &drivers) { ide_driver_t *driver = list_entry(p, ide_driver_t, drivers); if (!try_module_get(driver->owner)) continue; - spin_unlock(&drivers_lock); if (driver->attach(drive) == 0) { module_put(driver->owner); drive->gendev.driver = &driver->gen_driver; + up(&ide_setting_sem); + up(&drivers_sem); return 0; } - spin_lock(&drivers_lock); module_put(driver->owner); } drive->gendev.driver = &idedefault_driver.gen_driver; - spin_unlock(&drivers_lock); + up(&ide_setting_sem); + up(&drivers_sem); if(idedefault_driver.attach(drive) != 0) panic("ide: default attach failed"); return 1; @@ -1619,6 +1865,7 @@ case HDIO_SCAN_HWIF: { hw_regs_t hw; + ide_hwif_t *hwif; int args[3]; if (!capable(CAP_SYS_RAWIO)) return -EACCES; if (copy_from_user(args, p, 3 * sizeof(int))) @@ -1627,14 +1874,18 @@ ide_init_hwif_ports(&hw, (unsigned long) args[0], (unsigned long) args[1], NULL); hw.irq = args[2]; - if (ide_register_hw(&hw, NULL) == -1) + if (ide_register_hw(&hw, &hwif) == -1) return -EIO; + hwif->user_dev = 1; return 0; } case HDIO_UNREGISTER_HWIF: if (!capable(CAP_SYS_RAWIO)) return -EACCES; - /* (arg > MAX_HWIFS) checked in function */ - ide_unregister(arg); + if(arg > MAX_HWIFS || arg < 0) + return -EINVAL; + if(!ide_hwifs[arg].user_dev) + return -EINVAL; + return ide_unregister_hwif(&ide_hwifs[arg]); return 0; case HDIO_SET_NICE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -1660,9 +1911,13 @@ * spot if we miss one somehow */ - spin_lock_irqsave(&ide_lock, flags); - + + /* FIXME: need to block new commands here, must + find a better approach! */ + HWGROUP(drive)->busy = 1; DRIVER(drive)->abort(drive, "drive reset"); + + spin_lock_irqsave(&ide_lock, flags); if(HWGROUP(drive)->handler) BUG(); @@ -2274,8 +2529,8 @@ drive->suspend_reset = 0; #ifdef CONFIG_PROC_FS if (drive->driver != &idedefault_driver) { - ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - ide_add_proc_entries(drive->proc, driver->proc, drive); + ide_add_proc_entries(drive->proc, generic_subdriver_entries, ide_drive_to_key(drive)); + ide_add_proc_entries(drive->proc, driver->proc, ide_drive_to_key(drive)); } #endif return 0; @@ -2300,6 +2555,7 @@ int ide_unregister_subdriver (ide_drive_t *drive) { unsigned long flags; + ide_proc_entry_t *dir; down(&ide_setting_sem); spin_lock_irqsave(&ide_lock, flags); @@ -2308,13 +2564,14 @@ up(&ide_setting_sem); return 1; } + dir = DRIVER(drive)->proc; + drive->driver = &idedefault_driver; + spin_unlock_irqrestore(&ide_lock, flags); #ifdef CONFIG_PROC_FS - ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc); + ide_remove_proc_entries(drive->proc, dir); ide_remove_proc_entries(drive->proc, generic_subdriver_entries); #endif auto_remove_settings(drive); - drive->driver = &idedefault_driver; - spin_unlock_irqrestore(&ide_lock, flags); up(&ide_setting_sem); spin_lock(&drives_lock); list_del_init(&drive->list); @@ -2340,7 +2597,8 @@ * on the IDE bus in case any should be attached to the * driver we have just registered. If so attach them. * - * Takes drivers_lock and drives_lock. + * Takes the drivers and drives lock. Should take the + * ide_sem but doesn't - FIXME ?? */ int ide_register_driver(ide_driver_t *driver) @@ -2351,9 +2609,11 @@ setup_driver_defaults(driver); + down(&drivers_sem); spin_lock(&drivers_lock); list_add(&driver->drivers, &drivers); spin_unlock(&drivers_lock); + up(&drivers_sem); INIT_LIST_HEAD(&list); spin_lock(&drives_lock); @@ -2389,9 +2649,11 @@ { ide_drive_t *drive; + down(&drivers_sem); spin_lock(&drivers_lock); list_del(&driver->drivers); spin_unlock(&drivers_lock); + up(&drivers_sem); driver_unregister(&driver->gen_driver); @@ -2505,7 +2767,8 @@ int index; for (index = 0; index < MAX_HWIFS; ++index) { - ide_unregister(index); + if(ide_unregister_hwif(&ide_hwifs[index])) + printk(KERN_ERR "ide: unload yet busy!\n"); if (ide_hwifs[index].dma_base) (void) ide_release_dma(&ide_hwifs[index]); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-cd.c linux-2.6.9/drivers/ide/ide-cd.c --- linux.vanilla-2.6.9/drivers/ide/ide-cd.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-cd.c 2004-12-02 17:31:48.000000000 +0000 @@ -366,7 +366,8 @@ * we cannot reliably check if drive can auto-close */ if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) - log = 0; + break; + log = 1; break; case UNIT_ATTENTION: /* @@ -388,6 +389,10 @@ struct request *failed_command, struct request_sense *sense) { + unsigned long sector; + unsigned long bio_sectors; + unsigned long valid; + if (!cdrom_log_sense(drive, failed_command, sense)) return; @@ -400,13 +405,43 @@ if (sense->sense_key == 0x05 && sense->asc == 0x24) return; + if (sense->error_code == 0x70) { /* Current Error */ + switch(sense->sense_key) { + case MEDIUM_ERROR: + case VOLUME_OVERFLOW: + case ILLEGAL_REQUEST: + if(!sense->valid) + break; + if(failed_command == NULL || !blk_fs_request(failed_command)) + break; + sector = (sense->information[0] << 24) | + (sense->information[1] << 16) | + (sense->information[2] << 8) | + (sense->information[3]); + + bio_sectors = bio_sectors(failed_command->bio); + if(bio_sectors < 4) + bio_sectors = 4; + if(drive->queue->hardsect_size == 2048) + sector <<= 2; /* Device sector size is 2K */ + sector &= ~(bio_sectors -1); + valid = (sector - failed_command->sector) << 9; + + if(valid < 0) + valid = 0; + if(sector < get_capacity(drive->disk) && + drive->probed_capacity - sector < 4 * 75) { + set_capacity(drive->disk, sector); + } + } + } #if VERBOSE_IDE_CD_ERRORS { int i; const char *s; char buf[80]; - printk ("ATAPI device %s:\n", drive->name); + printk (KERN_ERR "ATAPI device %s:\n", drive->name); if (sense->error_code==0x70) printk(" Error: "); else if (sense->error_code==0x71) @@ -456,7 +491,7 @@ s = "(reserved error code)"; } - printk(" %s -- (asc=0x%02x, ascq=0x%02x)\n", + printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n", s, sense->asc, sense->ascq); if (failed_command != NULL) { @@ -478,7 +513,7 @@ lo = mid+1; } - printk (" The failed \"%s\" packet command was: \n \"", s); + printk (KERN_ERR " The failed \"%s\" packet command was: \n \"", s); for (i=0; icmd); i++) printk ("%02x ", failed_command->cmd[i]); printk ("\"\n"); @@ -491,13 +526,13 @@ */ if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; - printk(" Command is %02d%% complete\n", progress / 0xffff); + printk(KERN_ERR " Command is %02d%% complete\n", progress / 0xffff); } if (sense->sense_key == ILLEGAL_REQUEST && (sense->sks[0] & 0x80) != 0) { - printk(" Error in %s byte %d", + printk(KERN_ERR " Error in %s byte %d", (sense->sks[0] & 0x40) != 0 ? "command packet" : "command data", (sense->sks[1] << 8) + sense->sks[2]); @@ -518,8 +553,8 @@ (sense->sense_key == NOT_READY && (sense->asc == 4 || sense->asc == 0x3a))) return; - - printk("%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", + + printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", drive->name, sense->error_code, sense->sense_key, sense->asc, sense->ascq); @@ -635,17 +670,22 @@ sense = failed->sense; failed->sense_len = rq->sense_len; } - + cdrom_analyze_sense_data(drive, failed, sense); /* * now end failed request */ - spin_lock_irqsave(&ide_lock, flags); - end_that_request_chunk(failed, 0, failed->data_len); - end_that_request_last(failed); - spin_unlock_irqrestore(&ide_lock, flags); + if(blk_fs_request(failed)) { + if(ide_end_dequeued_request(drive, failed, 0, failed->hard_nr_sectors)) + BUG(); + } else { + spin_lock_irqsave(&ide_lock, flags); + end_that_request_chunk(failed, 0, failed->data_len); + end_that_request_last(failed); + spin_unlock_irqrestore(&ide_lock, flags); + } } - - cdrom_analyze_sense_data(drive, failed, sense); + else + cdrom_analyze_sense_data(drive, NULL , sense); } if (!rq->current_nr_sectors && blk_fs_request(rq)) @@ -659,6 +699,13 @@ ide_end_request(drive, uptodate, nsectors); } +static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat) +{ + if(stat & 0x80) + return; + ide_dump_status(drive, msg, stat); +} + /* Returns 0 if the request should be continued. Returns 1 if the request was ended. */ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) @@ -787,16 +834,16 @@ sense_key == DATA_PROTECT) { /* No point in retrying after an illegal request or data protect error.*/ - ide_dump_status (drive, "command error", stat); + ide_dump_status_no_sense (drive, "command error", stat); do_end_request = 1; } else if (sense_key == MEDIUM_ERROR) { /* No point in re-trying a zillion times on a bad * sector... If we got here the error is not correctable */ - ide_dump_status (drive, "media error (bad sector)", stat); + ide_dump_status_no_sense (drive, "media error (bad sector)", stat); do_end_request = 1; } else if (sense_key == BLANK_CHECK) { /* Disk appears blank ?? */ - ide_dump_status (drive, "media error (blank)", stat); + ide_dump_status_no_sense (drive, "media error (blank)", stat); do_end_request = 1; } else if ((err & ~ABRT_ERR) != 0) { /* Go to the default handler @@ -808,13 +855,27 @@ do_end_request = 1; } - if (do_end_request) - cdrom_end_request(drive, 0); + /* End a request through request sense analysis when we have + sense data. We need this in order to perform end of media + processing */ + + if (do_end_request) { + if (stat & ERR_STAT) { + unsigned long flags; + spin_lock_irqsave(&ide_lock, flags); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + spin_unlock_irqrestore(&ide_lock, flags); - /* If we got a CHECK_CONDITION status, - queue a request sense command. */ - if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, NULL, NULL); + cdrom_queue_request_sense(drive, rq->sense, rq); + } + else cdrom_end_request(drive, 0); + } else { + /* If we got a CHECK_CONDITION status, + queue a request sense command. */ + if (stat & ERR_STAT) + cdrom_queue_request_sense(drive, NULL, NULL); + } } else { blk_dump_rq_flags(rq, "ide-cd: bad rq"); cdrom_end_request(drive, 0); @@ -876,7 +937,7 @@ } else if (info->cmd == WRITE) { info->dma = !HWIF(drive)->ide_dma_write(drive); } else { - printk("ide-cd: DMA set, but not allowed\n"); + printk(KERN_WARNING "ide-cd: DMA set, but not allowed\n"); } } @@ -897,7 +958,11 @@ return ide_started; } else { /* packet command */ - HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); + unsigned long flags; + spin_lock_irqsave(&ide_lock, flags); + HWIF(drive)->OUTBSYNC(drive, WIN_PACKETCMD, IDE_COMMAND_REG); + ndelay(400); + spin_unlock_irqrestore(&ide_lock, flags); return (*handler) (drive); } } @@ -1013,7 +1078,7 @@ return 0; else if (ireason == 0) { /* Whoops... The drive is expecting to receive data from us! */ - printk("%s: read_intr: Drive wants to transfer data the " + printk(KERN_ERR "%s: read_intr: Drive wants to transfer data the " "wrong way!\n", drive->name); /* Throw some data at the drive so it doesn't hang @@ -1031,7 +1096,7 @@ return 0; } else { /* Drive wants a command packet, or invalid ireason... */ - printk("%s: read_intr: bad interrupt reason %x\n", drive->name, + printk(KERN_ERR "%s: read_intr: bad interrupt reason %x\n", drive->name, ireason); } @@ -1084,7 +1149,7 @@ /* If we're not done filling the current buffer, complain. Otherwise, complete the command normally. */ if (rq->current_nr_sectors > 0) { - printk ("%s: cdrom_read_intr: data underrun (%d blocks)\n", + printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n", drive->name, rq->current_nr_sectors); rq->flags |= REQ_FAILED; cdrom_end_request(drive, 0); @@ -1101,12 +1166,12 @@ of at least SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */ if ((len % SECTOR_SIZE) != 0) { - printk ("%s: cdrom_read_intr: Bad transfer size %d\n", + printk (KERN_ERR "%s: cdrom_read_intr: Bad transfer size %d\n", drive->name, len); if (CDROM_CONFIG_FLAGS(drive)->limit_nframes) - printk (" This drive is not supported by this version of the driver\n"); + printk (KERN_ERR " This drive is not supported by this version of the driver\n"); else { - printk (" Trying to limit transfer sizes\n"); + printk (KERN_ERR " Trying to limit transfer sizes\n"); CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1; } cdrom_end_request(drive, 0); @@ -1220,7 +1285,7 @@ paranoid and check. */ if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) && (rq->sector & (sectors_per_frame - 1))) { - printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n", + printk(KERN_ERR "%s: cdrom_read_from_buffer: buffer botch (%ld)\n", drive->name, (long)rq->sector); cdrom_end_request(drive, 0); return -1; @@ -1255,7 +1320,7 @@ /* Sanity check... */ if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) && (rq->sector & (sectors_per_frame - 1))) { - printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n", + printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n", drive->name, rq->current_nr_sectors); cdrom_end_request(drive, 0); return ide_stopped; @@ -1480,7 +1545,7 @@ rq->sense_len += thislen; } else { confused: - printk ("%s: cdrom_pc_intr: The drive " + printk (KERN_ERR "%s: cdrom_pc_intr: The drive " "appears confused (ireason = 0x%02x)\n", drive->name, ireason); rq->flags |= REQ_FAILED; @@ -1594,7 +1659,7 @@ return 0; else if (ireason == 2) { /* Whoops... The drive wants to send data. */ - printk("%s: write_intr: wrong transfer direction!\n", + printk(KERN_ERR "%s: write_intr: wrong transfer direction!\n", drive->name); while (len > 0) { @@ -1604,7 +1669,7 @@ } } else { /* Drive wants a command packet, or invalid ireason... */ - printk("%s: write_intr: bad interrupt reason %x\n", + printk(KERN_ERR "%s: write_intr: bad interrupt reason %x\n", drive->name, ireason); } @@ -1670,7 +1735,7 @@ */ if (dma) { if (dma_error) { - printk("ide-cd: dma error\n"); + printk(KERN_ERR "ide-cd: dma error\n"); __ide_dma_off(drive); return DRIVER(drive)->error(drive, "dma error", stat); } @@ -1735,7 +1800,7 @@ } if (!ptr) { - printk("%s: confused, missing data\n", drive->name); + printk(KERN_ERR "%s: confused, missing data\n", drive->name); break; } @@ -1797,7 +1862,7 @@ if (dma) { info->dma = 0; if ((dma_error = HWIF(drive)->ide_dma_end(drive))) { - printk("ide-cd: write dma error\n"); + printk(KERN_ERR "ide-cd: write dma error\n"); __ide_dma_off(drive); } } @@ -1830,7 +1895,7 @@ */ uptodate = 1; if (rq->current_nr_sectors > 0) { - printk("%s: write_intr: data underrun (%d blocks)\n", + printk(KERN_ERR "%s: write_intr: data underrun (%d blocks)\n", drive->name, rq->current_nr_sectors); uptodate = 0; } @@ -1851,7 +1916,7 @@ int this_transfer; if (!rq->current_nr_sectors) { - printk("ide-cd: write_intr: oops\n"); + printk(KERN_ERR "ide-cd: write_intr: oops\n"); break; } @@ -1995,7 +2060,7 @@ ide_stall_queue(drive, IDECD_SEEK_TIMER); return ide_stopped; } - printk ("%s: DSC timeout\n", drive->name); + printk (KERN_ERR "%s: DSC timeout\n", drive->name); } CDROM_CONFIG_FLAGS(drive)->seeking = 0; } @@ -2131,7 +2196,7 @@ if (stat != 0 && sense->sense_key == ILLEGAL_REQUEST && (sense->asc == 0x24 || sense->asc == 0x20)) { - printk ("%s: door locking not supported\n", + printk (KERN_ERR "%s: door locking not supported\n", drive->name); CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; stat = 0; @@ -2249,7 +2314,7 @@ GFP_KERNEL); info->toc = toc; if (toc == NULL) { - printk ("%s: No cdrom TOC buffer!\n", drive->name); + printk (KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name); return -ENOMEM; } } @@ -2268,6 +2333,9 @@ toc->capacity = 0x1fffff; set_capacity(drive->disk, toc->capacity * sectors_per_frame); + /* Save a private copy of te TOC capacity for error handling */ + drive->probed_capacity = toc->capacity * sectors_per_frame; + blk_queue_hardsect_size(drive->queue, sectors_per_frame << SECTOR_BITS); @@ -2382,6 +2450,7 @@ if (!stat && (last_written > toc->capacity)) { toc->capacity = last_written; set_capacity(drive->disk, toc->capacity * sectors_per_frame); + drive->probed_capacity = toc->capacity * sectors_per_frame; } /* Remember that we've read this stuff. */ @@ -2930,7 +2999,7 @@ if (drive->media == ide_optical) { CDROM_CONFIG_FLAGS(drive)->mo_drive = 1; CDROM_CONFIG_FLAGS(drive)->ram = 1; - printk("%s: ATAPI magneto-optical drive\n", drive->name); + printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name); return nslots; } @@ -3018,7 +3087,7 @@ /* don't print speed if the drive reported 0. */ - printk("%s: ATAPI", drive->name); + printk(KERN_INFO "%s: ATAPI", drive->name); if (CDROM_CONFIG_FLAGS(drive)->max_speed) printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed); printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM"); @@ -3262,7 +3331,7 @@ #endif if (ide_cdrom_register(drive, nslots)) { - printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); + printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); info->devinfo.handle = NULL; return 1; } @@ -3289,7 +3358,7 @@ struct gendisk *g = drive->disk; if (ide_unregister_subdriver(drive)) { - printk("%s: %s: failed to ide_unregister_subdriver\n", + printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n", __FUNCTION__, drive->name); return 1; } @@ -3300,7 +3369,7 @@ if (info->changer_info != NULL) kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom(devinfo)) - printk("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); + printk(KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree(info); drive->driver_data = NULL; blk_queue_prep_rq(drive->queue, NULL); @@ -3452,21 +3521,21 @@ /* skip drives that we were told to ignore */ if (ignore != NULL) { if (strstr(ignore, drive->name)) { - printk("ide-cd: ignoring drive %s\n", drive->name); + printk(KERN_INFO "ide-cd: ignoring drive %s\n", drive->name); goto failed; } } if (drive->scsi) { - printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); + printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); goto failed; } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { - printk("%s: Can't allocate a cdrom structure\n", drive->name); + printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name); goto failed; } if (ide_register_subdriver(drive, &ide_cdrom_driver)) { - printk("%s: Failed to register the driver with ide.c\n", + printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name); kfree(info); goto failed; @@ -3490,7 +3559,7 @@ if (info->changer_info != NULL) kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom(devinfo)) - printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); + printk (KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree(info); drive->driver_data = NULL; goto failed; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-disk.c linux-2.6.9/drivers/ide/ide-disk.c --- linux.vanilla-2.6.9/drivers/ide/ide-disk.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-disk.c 2004-12-03 12:37:33.000000000 +0000 @@ -88,6 +88,10 @@ { unsigned long lba_sects, chs_sects, head, tail; + /* No non-LBA info .. so valid! */ + if (id->cyls == 0) + return 1; + /* * The ATA spec tells large drives to return * C/H/S = 16383/16/63 independent of their size. @@ -987,13 +991,14 @@ static inline void idedisk_check_hpa(ide_drive_t *drive) { - unsigned long long capacity, set_max; + unsigned long long capacity, set_max = 0; int lba48 = idedisk_supports_lba48(drive->id); + capacity = drive->capacity64; if (lba48) set_max = idedisk_read_native_max_address_ext(drive); - else + if (set_max == 0) /* LBA28 or LBA48 failed */ set_max = idedisk_read_native_max_address(drive); if (set_max <= capacity) @@ -1009,7 +1014,8 @@ if (!drive->stroke) return; - if (lba48) + /* Some maxtor support LBA48 but do not accept LBA48 set max... */ + if (lba48 || set_max < (1ULL << 28)) set_max = idedisk_set_max_address_ext(drive, set_max); else set_max = idedisk_set_max_address(drive, set_max); @@ -1184,24 +1190,30 @@ static int proc_idedisk_read_cache (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; char *out = page; int len; - if (drive->id_read) + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if (drive && drive->id_read) len = sprintf(out,"%i\n", drive->id->buf_size / 2); else len = sprintf(out,"(none)\n"); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_idedisk_read_smart_thresholds (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; + ide_drive_t *drive; int len = 0, i = 0; - if (!get_smart_thresholds(drive, page)) { + down(&ide_cfg_sem); + + drive = ide_drive_from_key(data); + if (drive && !get_smart_thresholds(drive, page)) { unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; @@ -1211,16 +1223,20 @@ } while (i < (SECTOR_WORDS * 2)); len = out - page; } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_idedisk_read_smart_values (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; + ide_drive_t *drive; int len = 0, i = 0; - if (!get_smart_values(drive, page)) { + down(&ide_cfg_sem); + + drive = ide_drive_from_key(data); + if (drive && !get_smart_values(drive, page)) { unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; @@ -1230,6 +1246,7 @@ } while (i < (SECTOR_WORDS * 2)); len = out - page; } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -1602,8 +1619,10 @@ if (id->buf_size) printk (" w/%dKiB Cache", id->buf_size/2); - printk(", CHS=%d/%d/%d", - drive->bios_cyl, drive->bios_head, drive->bios_sect); + if(drive->bios_cyl) + printk(", CHS=%d/%d/%d", + drive->bios_cyl, drive->bios_head, drive->bios_sect); + if (drive->using_dma) (void) HWIF(drive)->ide_dma_verbose(drive); printk("\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-dma.c linux-2.6.9/drivers/ide/ide-dma.c --- linux.vanilla-2.6.9/drivers/ide/ide-dma.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-dma.c 2004-11-17 19:16:38.000000000 +0000 @@ -128,7 +128,6 @@ { "CD-532E-A" , "ALL" }, { "E-IDE CD-ROM CR-840", "ALL" }, { "CD-ROM Drive/F5A", "ALL" }, - { "RICOH CD-R/RW MP7083A", "ALL" }, { "WPI CDD-820", "ALL" }, { "SAMSUNG CD-ROM SC-148C", "ALL" }, { "SAMSUNG CD-ROM SC-148F", "ALL" }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-io.c linux-2.6.9/drivers/ide/ide-io.c --- linux.vanilla-2.6.9/drivers/ide/ide-io.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-io.c 2004-11-30 13:32:44.000000000 +0000 @@ -189,6 +189,62 @@ EXPORT_SYMBOL(ide_end_request); /** + * ide_end_dequeued_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * Complete an I/O that is no longer on the request queue. This + * typically occurs when we pull the request and issue a REQUEST_SENSE. + * We must still finish the old request but we must not tamper with the + * queue in the meantime. + * + * NOTE: This path does not handle barrier, but barrier is not supported + * on ide-cd anyway. + */ + +int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + + 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) && 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 + */ + if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { + drive->state = 0; + HWGROUP(drive)->hwif->ide_dma_on(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); + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ide_end_dequeued_request); + +/** * ide_complete_pm_request - end the current Power Management request * @drive: target drive * @rq: request @@ -556,30 +612,38 @@ * This differs fundamentally from ide_error because in * this case the command is doing just fine when we * blow it away. + * + * FIXME: need to fix locking corner cases */ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg) { ide_hwif_t *hwif; struct request *rq; + unsigned long flags; - if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + spin_lock_irqsave(&ide_lock, flags); + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) { + spin_unlock_irqrestore(&ide_lock, flags); return ide_stopped; - + } hwif = HWIF(drive); /* retry only "normal" I/O: */ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { rq->errors = 1; + spin_unlock_irqrestore(&ide_lock, flags); ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } if (rq->flags & REQ_DRIVE_TASKFILE) { rq->errors = 1; + spin_unlock_irqrestore(&ide_lock, flags); ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } rq->errors |= ERROR_RESET; + spin_unlock_irqrestore(&ide_lock, flags); DRIVER(drive)->end_request(drive, 0, 0); return ide_stopped; } @@ -1395,6 +1459,13 @@ return IRQ_NONE; } + if (hwif->polling) { + /* We took an interrupt during a polled drive retune. + This should go away eventually when that code uses + the polling logic like do_reset1 */ + spin_unlock_irqrestore(&ide_lock, flags); + return IRQ_HANDLED; + } if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) { /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-iops.c linux-2.6.9/drivers/ide/ide-iops.c --- linux.vanilla-2.6.9/drivers/ide/ide-iops.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-iops.c 2004-11-30 11:21:50.000000000 +0000 @@ -107,6 +107,74 @@ EXPORT_SYMBOL(default_hwif_iops); /* + * Interface removed + */ + +static u8 ide_no_inb(unsigned long port) +{ + return 0xFF; +} + +static u16 ide_no_inw (unsigned long port) +{ + return 0xFFFF; +} + +static void ide_no_insw (unsigned long port, void *addr, u32 count) +{ +} + +static u32 ide_no_inl (unsigned long port) +{ + return 0xFFFFFFFF; +} + +static void ide_no_insl (unsigned long port, void *addr, u32 count) +{ +} + +static void ide_no_outb (u8 val, unsigned long port) +{ +} + +static void ide_no_outbsync (ide_drive_t *drive, u8 addr, unsigned long port) +{ +} + +static void ide_no_outw (u16 val, unsigned long port) +{ +} + +static void ide_no_outsw (unsigned long port, void *addr, u32 count) +{ +} + +static void ide_no_outl (u32 val, unsigned long port) +{ +} + +static void ide_no_outsl (unsigned long port, void *addr, u32 count) +{ +} + +void removed_hwif_iops (ide_hwif_t *hwif) +{ + hwif->OUTB = ide_no_outb; + hwif->OUTBSYNC = ide_no_outbsync; + hwif->OUTW = ide_no_outw; + hwif->OUTL = ide_no_outl; + hwif->OUTSW = ide_no_outsw; + hwif->OUTSL = ide_no_outsl; + hwif->INB = ide_no_inb; + hwif->INW = ide_no_inw; + hwif->INL = ide_no_inl; + hwif->INSW = ide_no_insw; + hwif->INSL = ide_no_insl; +} + +EXPORT_SYMBOL(removed_hwif_iops); + +/* * MMIO operations, typically used for SATA controllers */ @@ -618,44 +686,15 @@ */ u8 eighty_ninty_three (ide_drive_t *drive) { -#if 0 - if (!HWIF(drive)->udma_four) + if(HWIF(drive)->udma_four == 0) + return 0; + if (!(drive->id->hw_config & 0x6000)) return 0; - - if (drive->id->major_rev_num) { - int hssbd = 0; - int i; - /* - * Determine highest Supported SPEC - */ - for (i=1; i<=15; i++) - if (drive->id->major_rev_num & (1<id->hw_config & 0x4000) && -#endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); - -#else - - return ((u8) ((HWIF(drive)->udma_four) && #ifndef CONFIG_IDEDMA_IVB - (drive->id->hw_config & 0x4000) && + if(!(drive->id->hw_config & 0x4000)) + return 0; #endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); -#endif + return 1; } EXPORT_SYMBOL(eighty_ninty_three); @@ -819,6 +858,11 @@ * It is gone.......... * * const char *msg == consider adding for verbose errors. + * + * Beware. If we timed out from a series of CRC errors and the timer + * expiry caused a switch to PIO mode and we take an IRQ as the drive times + * out about the same moment we may be entering this function with a + * pending interrupt. */ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) { @@ -836,20 +880,20 @@ /* * Don't use ide_wait_cmd here - it will - * attempt to set_geometry and recalibrate, - * but for some reason these don't work at - * this point (lost interrupt). - */ - /* - * Select the drive, and issue the SETFEATURES command + * attempt to set_geometry and recalibrate, We can't + * do that here as we may be in the IRQ handler already + * + * Select the drive, and issue the SETFEATURES command in + * polled mode. */ disable_irq_nosync(hwif->irq); /* - * FIXME: we race against the running IRQ here if + * We race against the running IRQ here if * this is called from non IRQ context. If we use - * disable_irq() we hang on the error path. Work - * is needed. + * disable_irq() we hang on the error path. Instead we + * must let the core code know the hwif is doing a polling + * recovery. */ udelay(1); @@ -860,23 +904,43 @@ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); hwif->OUTB(speed, IDE_NSECTOR_REG); hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG); - hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG); - if ((IDE_CONTROL_REG) && (drive->quirk_list == 2)) + hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); + /* The status bits are not valid for 400nS */ + udelay(1); + + /* Drive status is now valid which means we can allow interrupts + to occur as they will see the drive as busy and will not + interfere erroneously. IRQ's for this drive will also be off + providing control and quirks allow for it */ + + if ((IDE_CONTROL_REG) && drive->quirk_list == 2) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); udelay(1); + + /* + * Tell the interrupt layer that we are doing polled recovery. + * Eventually this should use the same mechanism do_reset does + * internally. + */ + + hwif->polling = 1; + /* * Wait for drive to become non-BUSY */ if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { - unsigned long flags, timeout; - local_irq_set(flags); + unsigned long timeout; + /* FIXME */ +/* spin_unlock_irq(&ide_lock); */ timeout = jiffies + WAIT_CMD; while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { if (time_after(jiffies, timeout)) break; } - local_irq_restore(flags); +/* spin_lock_irq(&ide_lock); */ } + + hwif->polling = 0; /* * Allow status to settle, then read it again. @@ -1188,7 +1252,8 @@ pre_reset(drive); SELECT_DRIVE(drive); udelay (20); - hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); + hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG); + ndelay(400); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL); spin_unlock_irqrestore(&ide_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-pnp.c linux-2.6.9/drivers/ide/ide-pnp.c --- linux.vanilla-2.6.9/drivers/ide/ide-pnp.c 2004-10-20 22:32:49.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-pnp.c 2004-11-04 12:42:56.000000000 +0000 @@ -57,7 +57,7 @@ { ide_hwif_t *hwif = pnp_get_drvdata(dev); if (hwif) { - ide_unregister(hwif->index); + ide_unregister_hwif(hwif); } else printk(KERN_ERR "idepnp: Unable to remove device, please report.\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-probe.c linux-2.6.9/drivers/ide/ide-probe.c --- linux.vanilla-2.6.9/drivers/ide/ide-probe.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-probe.c 2004-11-19 17:17:14.000000000 +0000 @@ -624,6 +624,7 @@ } hwif->gendev.release = hwif_release_dev; device_register(&hwif->gendev); + hwif->configured = 1; } static int wait_hwif_ready(ide_hwif_t *hwif) @@ -662,6 +663,42 @@ return rc; } +/** + * ide_undecoded_slave - look for bad CF adapters + * @hwif: interface + * + * Analyse the drives on the interface and attempt to decide if we + * have the same drive viewed twice. This occurs with crap CF adapters + * and PCMCIA sometimes. + */ + +void ide_undecoded_slave(ide_hwif_t *hwif) +{ + ide_drive_t *drive0 = &hwif->drives[0]; + ide_drive_t *drive1 = &hwif->drives[1]; + + if (drive0->present == 0 || drive1->present == 0) + return; + + /* If the models don't match they are not the same product */ + if (strcmp(drive0->id->model, drive1->id->model)) + return; + /* Serial numbers do not match */ + if(strncmp(drive0->id->serial_no, drive1->id->serial_no, 20)) + return; + /* No serial number, thankfully very rare for CF */ + if (drive0->id->serial_no[0] == 0) + return; + /* Has a serial number but is warped */ + if (!strstr(drive0->id->model, "Integrated Technology Express")) + return; + /* Appears to be an IDE flash adapter with decode bugs */ + printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n"); + drive1->present = 0; +} + +EXPORT_SYMBOL(ide_undecoded_slave); + /* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. @@ -736,18 +773,6 @@ ide_drive_t *drive = &hwif->drives[unit]; drive->dn = (hwif->channel ? 2 : 0) + unit; (void) probe_for_drive(drive); - if (drive->present && hwif->present && unit == 1) { - if (strcmp(hwif->drives[0].id->model, drive->id->model) == 0 && - /* Don't do this for noprobe or non ATA */ - strcmp(drive->id->model, "UNKNOWN") && - /* And beware of confused Maxtor drives that go "M0000000000" - "The SN# is garbage in the ID block..." [Eric] */ - strncmp(drive->id->serial_no, "M0000000000000000000", 20) && - strncmp(hwif->drives[0].id->serial_no, drive->id->serial_no, 20) == 0) { - printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n"); - drive->present = 0; - } - } if (drive->present && !hwif->present) { hwif->present = 1; if (hwif->chipset != ide_4drives || @@ -821,13 +846,18 @@ } static int hwif_init(ide_hwif_t *hwif); -int probe_hwif_init (ide_hwif_t *hwif) + +int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)) { probe_hwif(hwif); + if(fixup != NULL) + fixup(hwif); hwif_init(hwif); if (hwif->present) { u16 unit = 0; + + for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; /* For now don't attach absent drives, we may @@ -841,6 +871,13 @@ return 0; } +EXPORT_SYMBOL(probe_hwif_init_with_fixup); + +int probe_hwif_init(ide_hwif_t *hwif) +{ + return probe_hwif_init_with_fixup(hwif, NULL); +} + EXPORT_SYMBOL(probe_hwif_init); #if MAX_HWIFS > 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-proc.c linux-2.6.9/drivers/ide/ide-proc.c --- linux.vanilla-2.6.9/drivers/ide/ide-proc.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-proc.c 2004-10-24 17:32:59.000000000 +0100 @@ -74,10 +74,10 @@ #include -static int proc_ide_write_config(struct file *file, const char __user *buffer, +static int do_proc_ide_write_config(struct file *file, const char __user *buffer, unsigned long count, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *)data; + ide_hwif_t *hwif = ide_hwif_from_key(data); ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup); ide_hwgroup_t *mategroup = NULL; unsigned long timeout; @@ -258,6 +258,16 @@ goto out1; } +static int proc_ide_write_config(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int ret; + down(&ide_cfg_sem); + ret = do_proc_ide_write_config(file, buffer, count, data); + up(&ide_cfg_sem); + return ret; +} + static int proc_ide_read_config (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -265,32 +275,44 @@ int len; #ifdef CONFIG_BLK_DEV_IDEPCI - ide_hwif_t *hwif = (ide_hwif_t *)data; - struct pci_dev *dev = hwif->pci_dev; - if ((hwif->pci_dev && hwif->pci_dev->vendor) && dev && dev->bus) { - int reg = 0; - - out += sprintf(out, "pci bus %02x device %02x vendor %04x " - "device %04x channel %d\n", - dev->bus->number, dev->devfn, - hwif->pci_dev->vendor, hwif->pci_dev->device, - hwif->channel); - do { - u8 val; - int rc = pci_read_config_byte(dev, reg, &val); - if (rc) { - printk("proc_ide_read_config: error %d reading" - " bus %02x dev %02x reg 0x%02x\n", - rc, dev->bus->number, dev->devfn, reg); - out += sprintf(out, "??%c", - (++reg & 0xf) ? ' ' : '\n'); - } else - out += sprintf(out, "%02x%c", - val, (++reg & 0xf) ? ' ' : '\n'); - } while (reg < 0x100); - } else -#endif /* CONFIG_BLK_DEV_IDEPCI */ - out += sprintf(out, "(none)\n"); + ide_hwif_t *hwif = ide_hwif_from_key(data); + + down(&ide_cfg_sem); + hwif = ide_hwif_from_key(data); + + if(hwif) + { + struct pci_dev *dev = hwif->pci_dev; + if ((hwif->pci_dev && hwif->pci_dev->vendor) && dev && dev->bus) + { + int reg = 0; + + out += sprintf(out, "pci bus %02x device %02x vendor %04x " + "device %04x channel %d\n", + dev->bus->number, dev->devfn, + hwif->pci_dev->vendor, hwif->pci_dev->device, + hwif->channel); + do { + u8 val; + int rc = pci_read_config_byte(dev, reg, &val); + if (rc) { + printk("proc_ide_read_config: error %d reading" + " bus %02x dev %02x reg 0x%02x\n", + rc, dev->bus->number, dev->devfn, reg); + out += sprintf(out, "??%c", + (++reg & 0xf) ? ' ' : '\n'); + } else + out += sprintf(out, "%02x%c", + val, (++reg & 0xf) ? ' ' : '\n'); + } while (reg < 0x100); + } + else + out += sprintf(out, "(none)\n"); + } +#else /* CONFIG_BLK_DEV_IDEPCI */ + out += sprintf(out, "(none)\n"); +#endif + up(&ide_cfg_sem); len = out - page; PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -298,69 +320,88 @@ static int proc_ide_read_imodel (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *) data; + ide_hwif_t *hwif; int len; - const char *name; + const char *name = ""; - /* - * Neither ide_unknown nor ide_forced should be set at this point. - */ - switch (hwif->chipset) { - case ide_generic: name = "generic"; break; - case ide_pci: name = "pci"; break; - case ide_cmd640: name = "cmd640"; break; - case ide_dtc2278: name = "dtc2278"; break; - case ide_ali14xx: name = "ali14xx"; break; - case ide_qd65xx: name = "qd65xx"; break; - case ide_umc8672: name = "umc8672"; break; - case ide_ht6560b: name = "ht6560b"; break; - case ide_pdc4030: name = "pdc4030"; break; - case ide_rz1000: name = "rz1000"; break; - case ide_trm290: name = "trm290"; break; - case ide_cmd646: name = "cmd646"; break; - case ide_cy82c693: name = "cy82c693"; break; - case ide_4drives: name = "4drives"; break; - case ide_pmac: name = "mac-io"; break; - default: name = "(unknown)"; break; + down(&ide_cfg_sem); + hwif = ide_hwif_from_key(data); + if(hwif) + { + /* + * Neither ide_unknown nor ide_forced should be set at this point. + */ + switch (hwif->chipset) { + case ide_generic: name = "generic"; break; + case ide_pci: name = "pci"; break; + case ide_cmd640: name = "cmd640"; break; + case ide_dtc2278: name = "dtc2278"; break; + case ide_ali14xx: name = "ali14xx"; break; + case ide_qd65xx: name = "qd65xx"; break; + case ide_umc8672: name = "umc8672"; break; + case ide_ht6560b: name = "ht6560b"; break; + case ide_pdc4030: name = "pdc4030"; break; + case ide_rz1000: name = "rz1000"; break; + case ide_trm290: name = "trm290"; break; + case ide_cmd646: name = "cmd646"; break; + case ide_cy82c693: name = "cy82c693"; break; + case ide_4drives: name = "4drives"; break; + case ide_pmac: name = "mac-io"; break; + default: name = "(unknown)"; break; + } } len = sprintf(page, "%s\n", name); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_mate (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *) data; + ide_hwif_t *hwif; int len; + down(&ide_cfg_sem); + hwif = ide_hwif_from_key(data); if (hwif && hwif->mate && hwif->mate->present) len = sprintf(page, "%s\n", hwif->mate->name); else len = sprintf(page, "(none)\n"); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_channel (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *) data; - int len; + ide_hwif_t *hwif; + int len = 0; - page[0] = hwif->channel ? '1' : '0'; - page[1] = '\n'; - len = 2; + down(&ide_cfg_sem); + hwif = ide_hwif_from_key(data); + if(hwif) { + page[0] = hwif->channel ? '1' : '0'; + page[1] = '\n'; + len = 2; + } + else + page[0] = '\n'; + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_identify (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; + ide_drive_t *drive; int len = 0, i = 0; int err = 0; len = sprintf(page, "\n"); + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if (drive) { unsigned short *val = (unsigned short *) page; @@ -378,17 +419,28 @@ len = out - page; } } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_settings (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; - ide_settings_t *setting = (ide_settings_t *) drive->settings; + ide_drive_t *drive; + ide_settings_t *setting; char *out = page; int len, rc, mul_factor, div_factor; + + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + + if(drive == NULL) + { + up(&ide_cfg_sem); + return -EIO; + } + setting = (ide_settings_t *) drive->settings; down(&ide_setting_sem); out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); @@ -410,15 +462,16 @@ } len = out - page; up(&ide_setting_sem); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } #define MAX_LEN 30 -static int proc_ide_write_settings(struct file *file, const char __user *buffer, +static int do_proc_ide_write_settings(struct file *file, const char __user *buffer, unsigned long count, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive = ide_drive_from_key(data); char name[MAX_LEN + 1]; int for_real = 0; unsigned long n; @@ -427,6 +480,9 @@ if (!capable(CAP_SYS_ADMIN)) return -EACCES; + + if (drive == NULL) + return -EIO; if (count >= PAGE_SIZE) return -EINVAL; @@ -507,23 +563,51 @@ return -EINVAL; } +static int proc_ide_write_settings(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int ret; + + down(&ide_cfg_sem); + ret = do_proc_ide_write_settings(file, buffer, count, data); + up(&ide_cfg_sem); + return ret; +} + int proc_ide_read_capacity (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) + { + up(&ide_cfg_sem); + return -EIO; + } + len = sprintf(page,"%llu\n", (long long) (DRIVER(drive)->capacity(drive))); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } int proc_ide_read_geometry (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; char *out = page; int len; + + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) + { + up(&ide_cfg_sem); + return -EIO; + } out += sprintf(out,"physical %d/%d/%d\n", drive->cyl, drive->head, drive->sect); @@ -531,6 +615,7 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); len = out - page; + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -539,52 +624,63 @@ static int proc_ide_read_dmodel (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; - struct hd_driveid *id = drive->id; + ide_drive_t *drive; + struct hd_driveid *id; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) + { + up(&ide_cfg_sem); + return -EIO; + } + + id = drive->id; len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)"); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_driver (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; - ide_driver_t *driver = drive->driver; + ide_drive_t *drive; + ide_driver_t *driver; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) + { + up(&ide_cfg_sem); + return -EIO; + } + + driver = drive->driver; + len = sprintf(page, "%s version %s\n", driver->name, driver->version); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_write_driver - (struct file *file, const char __user *buffer, unsigned long count, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - char name[32]; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (count > 31) - count = 31; - if (copy_from_user(name, buffer, count)) - return -EFAULT; - name[count] = '\0'; - if (ide_replace_subdriver(drive, name)) - return -EINVAL; - return count; -} - static int proc_ide_read_media (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; const char *media; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) + { + up(&ide_cfg_sem); + return -EIO; + } + switch (drive->media) { case ide_disk: media = "disk\n"; break; @@ -599,11 +695,12 @@ } strcpy(page,media); len = strlen(media); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static ide_proc_entry_t generic_drive_entries[] = { - { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver }, + { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, NULL }, { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL }, { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL }, { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL }, @@ -655,7 +752,7 @@ drive->proc = proc_mkdir(drive->name, parent); if (drive->proc) - ide_add_proc_entries(drive->proc, generic_drive_entries, drive); + ide_add_proc_entries(drive->proc, generic_drive_entries, ide_drive_to_key(drive)); sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); ent = proc_symlink(drive->name, proc_ide_root, name); if (!ent) return; @@ -707,7 +804,7 @@ hwif->proc = proc_mkdir(hwif->name, proc_ide_root); if (!hwif->proc) return; - ide_add_proc_entries(hwif->proc, hwif_entries, hwif); + ide_add_proc_entries(hwif->proc, hwif_entries, ide_hwif_to_key(hwif)); } create_proc_ide_drives(hwif); } @@ -724,24 +821,30 @@ EXPORT_SYMBOL_GPL(ide_pci_create_host_proc); #endif +void destroy_proc_ide_interface(ide_hwif_t *hwif) +{ + int exist = (hwif->proc != NULL); +#if 0 + if (!hwif->present) + continue; +#endif + if (exist) { + destroy_proc_ide_drives(hwif); + ide_remove_proc_entries(hwif->proc, hwif_entries); + remove_proc_entry(hwif->name, proc_ide_root); + hwif->proc = NULL; + } +} + +EXPORT_SYMBOL(destroy_proc_ide_interface); + void destroy_proc_ide_interfaces(void) { int h; for (h = 0; h < MAX_HWIFS; h++) { ide_hwif_t *hwif = &ide_hwifs[h]; - int exist = (hwif->proc != NULL); -#if 0 - if (!hwif->present) - continue; -#endif - if (exist) { - destroy_proc_ide_drives(hwif); - ide_remove_proc_entries(hwif->proc, hwif_entries); - remove_proc_entry(hwif->name, proc_ide_root); - hwif->proc = NULL; - } else - continue; + destroy_proc_ide_interface(hwif); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/ide-taskfile.c linux-2.6.9/drivers/ide/ide-taskfile.c --- linux.vanilla-2.6.9/drivers/ide/ide-taskfile.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/ide-taskfile.c 2004-10-16 22:38:43.000000000 +0100 @@ -527,7 +527,11 @@ int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf) { - return ide_diag_taskfile(drive, args, 0, buf); + ide_hwif_t *hwif = HWIF(drive); + if(hwif->raw_taskfile) + return hwif->raw_taskfile(drive, args, buf); + else + return ide_diag_taskfile(drive, args, 0, buf); } EXPORT_SYMBOL(ide_raw_taskfile); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/Kconfig linux-2.6.9/drivers/ide/Kconfig --- linux.vanilla-2.6.9/drivers/ide/Kconfig 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/Kconfig 2004-11-15 23:35:49.000000000 +0000 @@ -166,6 +166,13 @@ Support for outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. +config BLK_DEV_DELKIN + tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" + depends on PCMCIA && PCI + help + Support for Delkin, ASKA, and Workbit Cardbus CompactFlash + Adapters. This may also work for similar SD and XD adapters. + config BLK_DEV_IDECD tristate "Include IDE/ATAPI CDROM support" ---help--- @@ -616,6 +623,12 @@ ; picture of the board at . +config BLK_DEV_IT8212 + tristate "IT8212 IDE support" + help + This driver adds support for the ITE 8212 IDE RAID controller in + both RAID and pass-through mode. + config BLK_DEV_NS87415 tristate "NS87415 chipset support" help diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/legacy/ide-cs.c linux-2.6.9/drivers/ide/legacy/ide-cs.c --- linux.vanilla-2.6.9/drivers/ide/legacy/ide-cs.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/legacy/ide-cs.c 2004-11-04 12:44:10.000000000 +0000 @@ -90,6 +90,7 @@ int ndev; dev_node_t node; int hd; + ide_hwif_t *hwif; } ide_info_t; static void ide_release(dev_link_t *); @@ -199,14 +200,14 @@ } /* ide_detach */ -static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq) +static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, ide_hwif_t **hwif) { hw_regs_t hw; memset(&hw, 0, sizeof(hw)); ide_init_hwif_ports(&hw, io, ctl, NULL); hw.irq = irq; hw.chipset = ide_pci; - return ide_register_hw(&hw, NULL); + return ide_register_hw_with_fixup(&hw, hwif, ide_undecoded_slave); } /*====================================================================== @@ -224,6 +225,7 @@ { client_handle_t handle = link->handle; ide_info_t *info = link->priv; + ide_hwif_t *hwif; tuple_t tuple; struct { u_short buf[128]; @@ -343,14 +345,17 @@ if (is_kme) outb(0x81, ctl_base+1); - /* retry registration in case device is still spinning up */ + /* retry registration in case device is still spinning up + + FIXME: now handled by IDE layer... ?? */ + for (hd = -1, i = 0; i < 10; i++) { - hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ); + hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, &hwif); if (hd >= 0) break; if (link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base + 0x10); hd = idecs_register(io_base + 0x10, ctl_base + 0x10, - link->irq.AssignedIRQ); + link->irq.AssignedIRQ, &hwif); if (hd >= 0) { io_base += 0x10; ctl_base += 0x10; @@ -373,6 +378,7 @@ info->node.major = ide_major[hd]; info->node.minor = 0; info->hd = hd; + info->hwif = hwif; link->dev = &info->node; printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", info->node.dev_name, link->conf.Vcc / 10, link->conf.Vcc % 10, @@ -411,7 +417,7 @@ if (info->ndev) { /* FIXME: if this fails we need to queue the cleanup somehow -- need to investigate the required PCMCIA magic */ - ide_unregister(info->hd); + ide_unregister_hwif(info->hwif); } info->ndev = 0; link->dev = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/alim15x3.c linux-2.6.9/drivers/ide/pci/alim15x3.c --- linux.vanilla-2.6.9/drivers/ide/pci/alim15x3.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/alim15x3.c 2004-11-29 15:55:20.000000000 +0000 @@ -8,6 +8,7 @@ * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org) * May be copied or modified under the terms of the GNU General Public License * Copyright (C) 2002 Alan Cox + * ALi (now ULi M5228) support by Clear Zhang * * (U)DMA capable version of ali 1533/1543(C), 1535(D) * @@ -799,7 +800,8 @@ 1, 11, 0, 12, 0, 14, 0, 15 }; int irq = -1; - hwif->irq = hwif->channel ? 15 : 14; + if(hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229) + hwif->irq = hwif->channel ? 15 : 14; if (isa_dev) { /* @@ -888,6 +890,7 @@ static struct pci_device_id alim15x3_pci_tbl[] = { { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/atiixp.c linux-2.6.9/drivers/ide/pci/atiixp.c --- linux.vanilla-2.6.9/drivers/ide/pci/atiixp.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/atiixp.c 2004-11-25 22:31:58.000000000 +0000 @@ -485,6 +485,7 @@ static struct pci_device_id atiixp_pci_tbl[] = { { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/cs5520.c linux-2.6.9/drivers/ide/pci/cs5520.c --- linux.vanilla-2.6.9/drivers/ide/pci/cs5520.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/cs5520.c 2004-11-18 13:32:14.000000000 +0000 @@ -287,7 +287,7 @@ if(pci_enable_device_bars(dev, 1<<2)) { printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); - return 1; + return -EBUSY; } pci_set_master(dev); if (pci_set_dma_mask(dev, 0xFFFFFFFF)) { @@ -305,8 +305,6 @@ ide_pci_setup_ports(dev, d, 1, 14, &index); - printk("Index.b %d %d\n", index.b.low, index.b.high); - mdelay(2000); if((index.b.low & 0xf0) != 0xf0) probe_hwif_init(&ide_hwifs[index.b.low]); if((index.b.high & 0xf0) != 0xf0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/delkin_cb.c linux-2.6.9/drivers/ide/pci/delkin_cb.c --- linux.vanilla-2.6.9/drivers/ide/pci/delkin_cb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/delkin_cb.c 2004-11-04 12:44:38.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * linux/drivers/ide/pci/delkin_cb.c + * + * Created 20 Oct 2004 by Mark Lord + * + * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter + * + * Modeled after the 16-bit PCMCIA driver: ide-cs.c + * + * This is slightly peculiar, in that it is a PCI driver, + * but is NOT an IDE PCI driver -- the IDE layer does not directly + * support hot insertion/removal of PCI interfaces, so this driver + * is unable to use the IDE PCI interfaces. Instead, it uses the + * same interfaces as the ide-cs (PCMCIA) driver uses. + * On the plus side, the driver is also smaller/simpler this way. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No chip documentation has yet been found, + * so these configuration values were pulled from + * a running Win98 system using "debug". + * This gives around 3MByte/second read performance, + * which is about 2/3 of what the chip is capable of. + * + * There is also a 4KByte mmio region on the card, + * but its purpose has yet to be reverse-engineered. + */ +static const u8 setup[] = { + 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, + 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, +}; + +static int __devinit +delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned long base; + hw_regs_t hw; + ide_hwif_t *hwif = NULL; + ide_drive_t *drive; + int i, rc; + + rc = pci_enable_device(dev); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); + return rc; + } + rc = pci_request_regions(dev, "delkin_cb"); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); + pci_disable_device(dev); + return rc; + } + base = pci_resource_start(dev, 0); + outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ + inb(base + 0x17); /* read status to clear interrupts */ + for (i = 0; i < sizeof(setup); ++i) { + if (setup[i]) + outb(setup[i], base + i); + } + pci_release_regions(dev); /* IDE layer handles regions itself */ + + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, base + 0x10, base + 0x1e); + hw.irq = dev->irq; + hw.chipset = ide_pci; /* this enables IRQ sharing */ + + rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave); + if (rc < 0) { + printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc); + pci_disable_device(dev); + return -ENODEV; + } + pci_set_drvdata(dev, hwif); + hwif->pci_dev = dev; + drive = &hwif->drives[0]; + if (drive->present) { + drive->io_32bit = 1; + drive->unmask = 1; + } + return 0; +} + +static void +delkin_cb_remove (struct pci_dev *dev) +{ + ide_hwif_t *hwif = pci_get_drvdata(dev); + + if (hwif) + ide_unregister_hwif(hwif); + pci_disable_device(dev); +} + +static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_WORKBIT, PCI_DEVICE_ID_WORKBIT_CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); + +static struct pci_driver driver = { + .name = "Delkin/ASKA/Workbit Cardbus IDE", + .id_table = delkin_cb_pci_tbl, + .probe = delkin_cb_probe, + .remove = delkin_cb_remove, +}; + +static int +delkin_cb_init (void) +{ + return pci_module_init(&driver); +} + +static void +delkin_cb_exit (void) +{ + pci_unregister_driver(&driver); +} + +module_init(delkin_cb_init); +module_exit(delkin_cb_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); +MODULE_LICENSE("GPL"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/generic.c linux-2.6.9/drivers/ide/pci/generic.c --- linux.vanilla-2.6.9/drivers/ide/pci/generic.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/generic.c 2004-11-18 13:29:12.000000000 +0000 @@ -41,6 +41,17 @@ #include "generic.h" +static int ide_generic_all; /* Set to claim all devices */ + +static int __init ide_generic_all_on(char *unused) +{ + ide_generic_all = 1; + printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n"); + return 1; +} + +__setup("all-generic-ide", ide_generic_all_on); + static unsigned int __init init_chipset_generic (struct pci_dev *dev, const char *name) { return 0; @@ -96,43 +107,54 @@ { ide_pci_device_t *d = &generic_chipsets[id->driver_data]; u16 command; + + /* Don't use the generic entry unless instructed to do so */ + if (id->driver_data == 0) + if(ide_generic_all == 0) + return -ENODEV; if (dev->vendor == PCI_VENDOR_ID_UMC && dev->device == PCI_DEVICE_ID_UMC_UM8886A && (!(PCI_FUNC(dev->devfn) & 1))) - return 1; /* UM8886A/BF pair */ + return -EAGAIN; /* UM8886A/BF pair */ if (dev->vendor == PCI_VENDOR_ID_OPTI && dev->device == PCI_DEVICE_ID_OPTI_82C558 && (!(PCI_FUNC(dev->devfn) & 1))) - return 1; + return -EAGAIN; pci_read_config_word(dev, PCI_COMMAND, &command); - if(!(command & PCI_COMMAND_IO)) - { + if(!(command & PCI_COMMAND_IO)) { printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name); - return 1; + return -ENODEV; } ide_setup_pci_device(dev, d); return 0; } +static void __devexit generic_remove_one(struct pci_dev *dev) +{ + ide_pci_remove_hwifs(dev); +} + static struct pci_device_id generic_pci_tbl[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, + { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, #ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, #endif - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, + /* Must come last. If you add entries adjust this table appropriately and the init_one code */ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, generic_pci_tbl); @@ -141,6 +163,7 @@ .name = "PCI_IDE", .id_table = generic_pci_tbl, .probe = generic_init_one, + .remove = generic_remove_one, }; static int generic_ide_init(void) @@ -150,6 +173,14 @@ module_init(generic_ide_init); +static void generic_ide_exit(void) +{ + return ide_pci_unregister_driver(&driver); +} + +module_exit(generic_ide_exit); + + MODULE_AUTHOR("Andre Hedrick"); MODULE_DESCRIPTION("PCI driver module for generic PCI IDE"); MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/generic.h linux-2.6.9/drivers/ide/pci/generic.h --- linux.vanilla-2.6.9/drivers/ide/pci/generic.h 2004-10-20 22:32:49.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/generic.h 2004-10-17 00:51:44.000000000 +0100 @@ -10,6 +10,13 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = { { /* 0 */ + .name = "Unknown", + .init_chipset = init_chipset_generic, + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = ON_BOARD, + },{ /* 1 */ .name = "NS87410", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, @@ -17,84 +24,84 @@ .autodma = AUTODMA, .enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, .bootable = ON_BOARD, - },{ /* 1 */ + },{ /* 2 */ .name = "SAMURAI", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - },{ /* 2 */ + },{ /* 3 */ .name = "HT6565", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - },{ /* 3 */ + },{ /* 4 */ .name = "UM8673F", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = NODMA, .bootable = ON_BOARD, - },{ /* 4 */ + },{ /* 5 */ .name = "UM8886A", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = NODMA, .bootable = ON_BOARD, - },{ /* 5 */ + },{ /* 6 */ .name = "UM8886BF", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = NODMA, .bootable = ON_BOARD, - },{ /* 6 */ + },{ /* 7 */ .name = "HINT_IDE", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - },{ /* 7 */ + },{ /* 8 */ .name = "VIA_IDE", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 8 */ + },{ /* 9 */ .name = "OPTI621V", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 9 */ + },{ /* 10 */ .name = "VIA8237SATA", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = OFF_BOARD, - },{ /* 10 */ + },{ /* 11 */ .name = "Piccolo0102", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 11 */ + },{ /* 12 */ .name = "Piccolo0103", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 12 */ + },{ /* 13 */ .name = "Piccolo0105", .init_chipset = init_chipset_generic, .init_hwif = init_hwif_generic, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/hpt366.c linux-2.6.9/drivers/ide/pci/hpt366.c --- linux.vanilla-2.6.9/drivers/ide/pci/hpt366.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/hpt366.c 2004-11-12 16:19:20.000000000 +0000 @@ -10,6 +10,11 @@ * donation of an ABit BP6 mainboard, processor, and memory acellerated * development and support. * + * + * Highpoint have their own driver (source except for the raid part) + * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz + * This may be useful to anyone wanting to work on the mainstream hpt IDE. + * * Note that final HPT370 support was done by force extraction of GPL. * * - add function for getting/setting power status of drive @@ -103,7 +108,10 @@ u8 c0, c1; p += sprintf(p, "\nController: %d\n", i); - p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]); + if(class_rev < 9) + p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]); + else + p += sprintf(p, "Chipset: HPT revision %d\n", class_rev); p += sprintf(p, "--------------- Primary Channel " "--------------- Secondary Channel " "--------------\n"); @@ -169,6 +177,12 @@ } #endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ +/* + * This wants fixing so that we do everything not by classrev + * (which breaks on the newest chips) but by creating an + * enumeration of chip variants and using that + */ + static u32 hpt_revision (struct pci_dev *dev) { u32 class_rev; @@ -466,7 +480,11 @@ { u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive)); - if (!(speed)) + if (!speed) + return 0; + + /* If we don't have any timings we can't do a lot */ + if (pci_get_drvdata(HWIF(drive)->pci_dev) == NULL) return 0; (void) hpt3xx_tune_chipset(drive, speed); @@ -886,7 +904,11 @@ /* * default to pci clock. make sure MA15/16 are set to output - * to prevent drives having problems with 40-pin cables. + * to prevent drives having problems with 40-pin cables. Needed + * for some drives such as IBM-DTLA which will not enter ready + * state on reset when PDIAG is a input. + * + * ToDo: should we set 0x21 when using PLL mode ? */ pci_write_config_byte(dev, 0x5b, 0x23); @@ -981,6 +1003,9 @@ * result in slow reads when using a 33MHz PCI clock. we also * don't like to use the PLL because it will cause glitches * on PRST/SRST when the HPT state engine gets reset. + * + * ToDo: Use 66MHz PLL when ATA133 devices are present on a + * 372 device so we can get ATA133 support */ if (pci_get_drvdata(dev)) goto init_hpt37X_done; @@ -1030,6 +1055,9 @@ } init_hpt37X_done: + if (!pci_get_drvdata(dev)) + printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n", + is_372n?"N":"", pll, freq); /* reset state engine */ pci_write_config_byte(dev, 0x50, 0x37); pci_write_config_byte(dev, 0x54, 0x37); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/it8172.c linux-2.6.9/drivers/ide/pci/it8172.c --- linux.vanilla-2.6.9/drivers/ide/pci/it8172.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/it8172.c 2004-11-18 13:33:22.000000000 +0000 @@ -290,7 +290,7 @@ { if ((!(PCI_FUNC(dev->devfn) & 1) || (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))) - return 1; /* IT8172 is more than only a IDE controller */ + return -EAGAIN; /* IT8172 is more than only a IDE controller */ ide_setup_pci_device(dev, &it8172_chipsets[id->driver_data]); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/it8212.c linux-2.6.9/drivers/ide/pci/it8212.c --- linux.vanilla-2.6.9/drivers/ide/pci/it8212.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/it8212.c 2004-11-25 22:43:16.000000000 +0000 @@ -0,0 +1,858 @@ +/* + * linux/drivers/ide/pci/it8212.c Version 0.08 November 2004 + * + * Copyright (C) 2004 Red Hat + * + * May be copied or modified under the terms of the GNU General Public License + * Based in part on the ITE vendor provided SCSI driver. + * + * Documentation available from + * http://www.ite.com.tw/pc/IT8212F_V04.pdf + * Some other documents are NDA. + * + * The ITE8212 isn't exactly a standard IDE controller. It has two + * modes. In pass through mode then it is an IDE controller. In its smart + * mode its actually quite a capable hardware raid controller disguised + * as an IDE controller. Smart mode only understands DMA read/write and + * identify, none of the fancier commands apply. + * + * Errata: + * o Rev 0x10 also requires master/slave hold the same DMA timings and + * cannot do ATAPI MWDMA. + * o The identify data for raid volumes lacks CHS info (technically ok) + * but also fails to set the LBA28 and other bits. We fix these in + * the IDE probe quirk code. + * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode + * raid then the controller firmware dies + * o Smart mode without RAID doesn't clear all the necessary identify + * bits to reduce the command set to the one used + * + * This has a few impacts on the driver + * - In pass through mode we do all the work you would expect + * - In smart mode the clocking set up is done by the controller generally + * but we must watch the other limits and filter. + * - There are a few extra vendor commands that actually talk to the + * controller but only work PIO with no IRQ. + * + * Vendor areas of the identify block in smart mode are used for the + * timing and policy set up. Each HDD in raid mode also has a serial + * block on the disk. The hardware extra commands are get/set chip status, + * rebuild, get rebuild status. + * + * In Linux the driver supports pass through mode as if the device was + * just another IDE controller. If the smart mode is running then + * volumes are managed by the controller firmware and each IDE "disk" + * is a raid volume. Even more cute - the controller can do automated + * hotplug and rebuild. + * + * The pass through controller itself is a little demented. It has a + * flaw that it has a single set of PIO/MWDMA timings per channel so + * non UDMA devices restrict each others performance. It also has a + * single clock source per channel so mixed UDMA100/133 performance + * isn't perfect and we have to pick a clock. Thankfully none of this + * matters in smart mode. ATAPI DMA is not currently supported. + * + * It seems the smart mode is a win for RAID1/RAID10 but otherwise not. + * + * TODO + * - ATAPI UDMA is ok but not MWDMA it seems + * - RAID configuration ioctls + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct it8212_dev +{ + unsigned int smart:1, /* Are we in smart raid mode */ + timing10:1; /* Rev 0x10 */ + u8 clock_mode; /* 0, ATA_50 or ATA_66 */ + u8 want[2][2]; /* Mode/Pri log for master slave */ + /* We need these for switching the clock when DMA goes on/off + The high byte is the 66Mhz timing */ + u16 pio[2]; /* Cached PIO values */ + u16 mwdma[2]; /* Cached MWDMA values */ + u16 udma[2]; /* Cached UDMA values (per drive) */ +}; + +#define ATA_66 0 +#define ATA_50 1 +#define ATA_ANY 2 + +#define UDMA_OFF 0 +#define MWDMA_OFF 0 + +/* + * We allow users to force the card into non raid mode without + * flashing the alternative BIOS. This is also neccessary right now + * for embedded platforms that cannot run a PC BIOS but are using this + * device. + */ + +static int it8212_noraid; + +/** + * it8212_program - program the PIO/MWDMA registers + * @drive: drive to tune + * + * Program the PIO/MWDMA timing for this channel according to the + * current clock. + */ + +static void it8212_program(ide_drive_t *drive, u16 timing) +{ + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + int channel = hwif->channel; + u8 conf; + + /* Program PIO/MWDMA timing bits */ + if(itdev->clock_mode == ATA_66) + conf = timing >> 8; + else + conf = timing & 0xFF; + pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf); +} + +/** + * it8212_program_udma - program the UDMA registers + * @drive: drive to tune + * + * Program the UDMA timing for this drive according to the + * current clock. + */ + +static void it8212_program_udma(ide_drive_t *drive, u16 timing) +{ + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + int channel = hwif->channel; + int unit = drive->select.b.unit; + u8 conf; + + /* Program UDMA timing bits */ + if(itdev->clock_mode == ATA_66) + conf = timing >> 8; + else + conf = timing & 0xFF; + if(itdev->timing10 == 0) + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf); + else { + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf); + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf); + } +} + + +/** + * it8212_clock_strategy + * @hwif: hardware interface + * + * Select between the 50 and 66Mhz base clocks to get the best + * results for this interface. + */ + +static void it8212_clock_strategy(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + + u8 unit = drive->select.b.unit; + ide_drive_t *pair = &hwif->drives[1-unit]; + + int clock, altclock; + u8 v; + int sel = 0; + + if(itdev->want[0][0] > itdev->want[1][0]) { + clock = itdev->want[0][1]; + altclock = itdev->want[1][1]; + } else { + clock = itdev->want[1][1]; + altclock = itdev->want[0][1]; + } + + /* Master doesn't care does the slave ? */ + if(clock == ATA_ANY) + clock = altclock; + + /* Nobody cares - keep the same clock */ + if(clock == ATA_ANY) + return; + /* No change */ + if(clock == itdev->clock_mode) + return; + + /* Load this into the controller ? */ + if(clock == ATA_66) + itdev->clock_mode = ATA_66; + else { + itdev->clock_mode = ATA_50; + sel = 1; + } + pci_read_config_byte(hwif->pci_dev, 0x50, &v); + v &= ~(1 << (1 + hwif->channel)); + v |= sel << (1 + hwif->channel); + pci_write_config_byte(hwif->pci_dev, 0x50, v); + + /* + * Reprogram the UDMA/PIO of the pair drive for the switch + * MWDMA will be dealt with by the dma switcher + */ + if(pair && itdev->udma[1-unit] != UDMA_OFF) { + it8212_program_udma(pair, itdev->udma[1-unit]); + it8212_program(pair, itdev->pio[1-unit]); + } + /* + * Reprogram the UDMA/PIO of our drive for the switch. + * MWDMA will be dealt with by the dma switcher + */ + if(itdev->udma[unit] != UDMA_OFF) { + it8212_program_udma(drive, itdev->udma[unit]); + it8212_program(drive, itdev->pio[unit]); + } +} + +/** + * it8212_ratemask - Compute available modes + * @drive: IDE drive + * + * Compute the available speeds for the devices on the interface. This + * is all modes to ATA133 clipped by drive cable setup. + */ + +static byte it8212_ratemask (ide_drive_t *drive) +{ + u8 mode = 4; + if (!eighty_ninty_three(drive)) + mode = min(mode, (u8)1); + return mode; +} + +/** + * it8212_tuneproc - tune a drive + * @drive: drive to tune + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller. By the time we are called the mode has been + * modified as neccessary to handle the absence of seperate + * master/slave timers for MWDMA/PIO. + * + * This code is only used in pass through mode. + */ + +static void it8212_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + + /* Spec says 89 ref driver uses 88 */ + static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; + static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; + + if(itdev->smart) + return; + + /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ + itdev->want[unit][1] = pio_want[mode_wanted]; + itdev->want[unit][0] = 1; /* PIO is lowest priority */ + itdev->pio[unit] = pio[mode_wanted]; + it8212_clock_strategy(drive); + it8212_program(drive, itdev->pio[unit]); +} + +/** + * it8212_tune_mwdma - tune a channel for MWDMA + * @drive: drive to set up + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller when doing MWDMA in pass through mode. The caller + * must manage the whole lack of per device MWDMA/PIO timings and + * the shared MWDMA/PIO timing register. + */ + +static void it8212_tune_mwdma (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = (void *)ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + int channel = hwif->channel; + u8 conf; + + static u16 dma[] = { 0x8866, 0x3222, 0x3121 }; + static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY }; + + itdev->want[unit][1] = mwdma_want[mode_wanted]; + itdev->want[unit][0] = 2; /* MWDMA is low priority */ + itdev->mwdma[unit] = dma[mode_wanted]; + itdev->udma[unit] = UDMA_OFF; + + /* UDMA bits off - Revision 0x10 do them in pairs */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(itdev->timing10) + conf |= channel ? 0x60: 0x18; + else + conf |= 1 << (3 + 2 * channel + unit); + pci_write_config_byte(hwif->pci_dev, 0x50, conf); + + it8212_clock_strategy(drive); + /* FIXME: do we need to program this ? */ + /* it8212_program(drive, itdev->mwdma[unit]); */ +} + +/** + * it8212_tune_udma - tune a channel for UDMA + * @drive: drive to set up + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller when doing UDMA modes in pass through. + */ + +static void it8212_tune_udma (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + int channel = hwif->channel; + u8 conf; + + static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 }; + static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 }; + + itdev->want[unit][1] = udma_want[mode_wanted]; + itdev->want[unit][0] = 3; /* UDMA is high priority */ + itdev->mwdma[unit] = MWDMA_OFF; + itdev->udma[unit] = udma[mode_wanted]; + if(mode_wanted >= 5) + itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */ + + /* UDMA on. Again revision 0x10 must do the pair */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(itdev->timing10) + conf &= channel ? 0x9F: 0xE7; + else + conf &= ~ (1 << (3 + 2 * channel + unit)); + pci_write_config_byte(hwif->pci_dev, 0x50, conf); + + it8212_clock_strategy(drive); + it8212_program_udma(drive, itdev->udma[unit]); + +} + +/** + * config_it8212_chipset_for_pio - set drive timings + * @drive: drive to tune + * @speed we want + * + * Compute the best pio mode we can for a given device. We must + * pick a speed that does not cause problems with the other device + * on the cable. + */ + +static void config_it8212_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + u8 unit = drive->select.b.unit; + ide_hwif_t *hwif = HWIF(drive); + ide_drive_t *pair = &hwif->drives[1-unit]; + u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL); + u8 pair_pio; + + /* We have to deal with this mess in pairs */ + if(pair != NULL) { + pair_pio = ide_get_best_pio_mode(pair, 4, 5, NULL); + /* Trim PIO to the slowest of the master/slave */ + if(pair_pio < set_pio) + set_pio = pair_pio; + } + it8212_tuneproc(drive, set_pio); + speed = XFER_PIO_0 + set_pio; + /* XXX - We trim to the lowest of the pair so the other drive + will always be fine at this point until we do hotplug passthru */ + + if (set_speed) + (void) ide_config_drive_speed(drive, speed); +} + +static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + config_it8212_chipset_for_pio(drive, set_speed); +} + +/** + * it8212_dma_read - DMA hook + * @drive: drive for DMA + * + * The IT8212 has a single timing register for MWDMA and for PIO + * operations. As we flip back and forth we have to reload the + * clock. In addition the rev 0x10 device only works if the same + * timing value is loaded into the master and slave UDMA clock + * so we must also reload that. + * + * FIXME: we could figure out in advance if we need to do reloads + */ + +static int it8212_dma_begin(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + if(itdev->mwdma[unit] != MWDMA_OFF) + it8212_program(drive, itdev->mwdma[unit]); + else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10) + it8212_program_udma(drive, itdev->udma[unit]); + return __ide_dma_begin(drive); +} + +/** + * it8212_dma_write - DMA hook + * @drive: drive for DMA stop + * + * The IT8212 has a single timing register for MWDMA and for PIO + * operations. As we flip back and forth we have to reload the + * clock. + */ + +static int it8212_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + int unit = drive->select.b.unit; + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + int ret = __ide_dma_end(drive); + if(itdev->mwdma[unit] != MWDMA_OFF) + it8212_program(drive, itdev->pio[unit]); + return ret; +} + + +/** + * it8212_tune_chipset - set controller timings + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Tune the ITE chipset for the desired mode. If we can't achieve + * the desired mode then tune for a lower one, but ultimately + * make the thing work. + */ + +static int it8212_tune_chipset (ide_drive_t *drive, byte xferspeed) +{ + + ide_hwif_t *hwif = HWIF(drive); + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + u8 speed = ide_rate_filter(it8212_ratemask(drive), xferspeed); + + switch(speed) { + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + it8212_tuneproc(drive, (speed - XFER_PIO_0)); + break; + /* MWDMA tuning is really hard because our MWDMA and PIO + timings are kept in the same place. We can switch in the + host dma on/off callbacks */ + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + if(!itdev->smart) + it8212_tune_mwdma(drive, (speed - XFER_MW_DMA_0)); + break; + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + if(!itdev->smart) + it8212_tune_udma(drive, (speed - XFER_UDMA_0)); + break; + default: + return 1; + } + /* + * In smart mode the clocking is done by the host controller + * snooping the mode we picked. The rest of it is not our problem + */ + return (ide_config_drive_speed(drive, speed)); +} + +/** + * config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by the IDE layer when it wants the timings set up. + */ + +static int config_chipset_for_dma (ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, it8212_ratemask(drive)); + + config_chipset_for_pio(drive, !speed); + + if (!speed) + return 0; + + if (ide_set_xfer_rate(drive, speed)) + return 0; + + if (!drive->init_speed) + drive->init_speed = speed; + + return ide_dma_enable(drive); +} + +/** + * it8212_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. If the drive isn't suitable for DMA or we hit + * other problems then we will drop down to PIO and set up + * PIO appropriately + */ + +static int it8212_config_drive_for_dma (ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct hd_driveid *id = drive->id; + + if ((id->capability & 1) != 0 && drive->autodma) { + /* Consult the list of known "bad" drives */ + if (__ide_dma_bad_drive(drive)) + goto fast_ata_pio; + + if ((id->field_valid & 4) && it8212_ratemask(drive)) { + if (id->dma_ultra & hwif->ultra_mask) { + /* Force if Capable UltraDMA */ + int dma = config_chipset_for_dma(drive); + if ((id->field_valid & 2) && !dma) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & hwif->mwdma_mask) || + (id->dma_1word & hwif->swdma_mask)) { + /* Force if Capable regular DMA modes */ + if (!config_chipset_for_dma(drive)) + goto no_dma_set; + } + } else if (__ide_dma_good_drive(drive) && + (id->eide_dma_time < 150)) { + /* Consult the list of known "good" drives */ + if (!config_chipset_for_dma(drive)) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + return hwif->ide_dma_on(drive); + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: +no_dma_set: + config_chipset_for_pio(drive, 1); + return hwif->ide_dma_off_quietly(drive); + } + /* IORDY not supported */ + return 0; +} + +/** + * init_chipset_it8212 - set up an ITE device + * @dev: PCI device + * @name: device name + * + * PCI chipset level initialize. Nothing to do. + */ + +static unsigned int __devinit init_chipset_it8212(struct pci_dev *dev, const char *name) +{ + return 0; +} + +/** + * ata66_it8212 - check for 80 pin cable + * @hwif: interface to check + * + * Check for the presence of an ATA66 capable cable on the + * interface. Problematic as it seems some cards don't have + * the needed logic onboard. + */ + +static unsigned int __devinit ata66_it8212(ide_hwif_t *hwif) +{ + /* The reference driver also only does disk side */ + return 1; +} + +/** + * it8212_fixup - post init callback + * @hwif: interface + * + * This callback is run after the drives have been probed but + * before anything gets attached. It allows drivers to do any + * final tuning that is needed, or fixups to work around bugs. + */ + +static void __devinit it8212_fixups(ide_hwif_t *hwif) +{ + struct it8212_dev *itdev = ide_get_hwifdata(hwif); + int i; + + if(!itdev->smart) { + /* + * If we are in pass through mode then not much + * needs to be done, but we do bother to clear the + * IRQ mask in case the drives are PIO (eg rev 0x10) + * for now. + */ + for (i = 0; i < 2; i++) { + ide_drive_t *drive = &hwif->drives[i]; + if(drive->present) + drive->unmask = 1; + } + return; + } + /* + * Perform fixups on smart mode. We need to "lose" some + * capabilities the firmware lacks but does not filter, and + * also patch up some capability bits that it forgets to set + * in RAID mode. + */ + + for(i = 0; i < 2; i++) { + ide_drive_t *drive = &hwif->drives[i]; + struct hd_driveid *id; + u16 *idbits; + + if(!drive->present) + continue; + id = drive->id; + idbits = (u16 *)drive->id; + + /* Check for RAID v native */ + if(strstr(id->model, "Integrated Technology Express")) { + /* In raid mode the ident block is slightly buggy */ + id->capability |= 3; /* LBA28, DMA */ + id->command_set_2 |= 0x0400; /* LBA48 valid */ + id->cfs_enable_2 |= 0x0400; /* LBA48 on */ + /* Reporting logic */ + printk(KERN_INFO "%s: IT8212 %sRAID %d volume", + drive->name, + idbits[147] ? "Bootable ":"", + idbits[129]); + if(idbits[129] != 1) + printk("(%dK stripe)", idbits[146]); + printk(".\n"); + /* Now the core code will have wrongly decided no DMA + so we need to fix this */ + hwif->ide_dma_off_quietly(drive); +#ifdef CONFIG_IDEDMA_ONLYDISK + if (drive->media == ide_disk) +#endif + hwif->ide_dma_check(drive); + } else { + /* Non RAID volume. Fixups to stop the core code + doing unsupported things */ + id->field_valid &= 1; + id->queue_depth = 0; + id->command_set_1 = 0; + id->command_set_2 &= 0xC400; + id->cfsse &= 0xC000; + id->cfs_enable_1 = 0; + id->cfs_enable_2 &= 0xC400; + id->csf_default &= 0xC000; + id->word127 = 0; + id->dlf = 0; + id->csfo = 0; + id->cfa_power = 0; + printk(KERN_INFO "%s: Performing identify fixups.\n", + drive->name); + } + } + +} + +/** + * init_hwif_it8212 - set up hwif structs + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The IT8212 + * requires several custom handlers so we override the default + * ide DMA handlers appropriately + */ + +static void __devinit init_hwif_it8212(ide_hwif_t *hwif) +{ + struct it8212_dev *idev = kmalloc(sizeof(struct it8212_dev), GFP_KERNEL); + u8 conf; + static char *mode[2] = { "pass through", "smart" }; + + if(idev == NULL) { + printk(KERN_ERR "it8212: out of memory, falling back to legacy behaviour.\n"); + goto fallback; + } + memset(idev, 0, sizeof(struct it8212_dev)); + ide_set_hwifdata(hwif, idev); + + /* Force the card into bypass mode if so requested */ + if (it8212_noraid) { + printk(KERN_INFO "it8212: forcing bypass mode.\n"); + + /* Reset local CPU, and set BIOS not ready */ + pci_write_config_byte(hwif->pci_dev, 0x5E, 0x01); + + /* Set to bypass mode, and reset PCI bus */ + pci_write_config_byte(hwif->pci_dev, 0x50, 0x00); + + pci_write_config_word(hwif->pci_dev, PCI_COMMAND, + PCI_COMMAND_PARITY | PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + pci_write_config_word(hwif->pci_dev, 0x40, 0xA0F3); + + pci_write_config_dword(hwif->pci_dev,0x4C, 0x02040204); + pci_write_config_byte(hwif->pci_dev, 0x42, 0x36); + pci_write_config_byte(hwif->pci_dev, PCI_LATENCY_TIMER, 0); + } + + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(conf & 1) { + idev->smart = 1; + hwif->atapi_dma = 0; + /* Long I/O's although allowed in LBA48 space cause the + onboard firmware to enter the twighlight zone */ + hwif->rqsize = 256; + } + + if(hwif->channel == 0) + printk(KERN_INFO "it8212: controller in %s mode.\n", + mode[idev->smart]); + + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if (conf & (1 << (1 + hwif->channel))) + idev->clock_mode = ATA_50; + else + idev->clock_mode = ATA_66; + + idev->want[0][1] = ATA_ANY; + idev->want[1][1] = ATA_ANY; + + /* + * Not in the docs but according to the reference driver + * this is neccessary. + */ + + pci_read_config_byte(hwif->pci_dev, 0x08, &conf); + if(conf == 0x10) { + idev->timing10 = 1; + hwif->atapi_dma = 0; + if(!idev->smart) + printk(KERN_WARNING "it8212: Revision 0x10, workarounds activated.\n"); + } + + hwif->speedproc = &it8212_tune_chipset; + hwif->tuneproc = &it8212_tuneproc; + + /* MWDMA/PIO clock switching for pass through mode */ + if(!idev->smart) { + hwif->ide_dma_begin = &it8212_dma_begin; + hwif->ide_dma_end = &it8212_dma_end; + } + + if (!hwif->dma_base) + goto fallback; + + hwif->ultra_mask = 0x7f; + hwif->mwdma_mask = 0x07; + hwif->swdma_mask = 0x07; + + hwif->ide_dma_check = &it8212_config_drive_for_dma; + if (!(hwif->udma_four)) + hwif->udma_four = ata66_it8212(hwif); + + /* + * The BIOS often doesn't set up DMA on this controller + * so we always do it. + */ + + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; + return; + +fallback: + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + return; +} + +#define DECLARE_ITE_DEV(name_str) \ + { \ + .name = name_str, \ + .init_chipset = init_chipset_it8212, \ + .init_hwif = init_hwif_it8212, \ + .channels = 2, \ + .autodma = AUTODMA, \ + .bootable = ON_BOARD, \ + .fixup = it8212_fixups \ + } + +static ide_pci_device_t it8212_chipsets[] __devinitdata = { + /* 0 */ DECLARE_ITE_DEV("IT8212"), +}; + +/** + * it8212_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an ITE8212 controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int __devinit it8212_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_setup_pci_device(dev, &it8212_chipsets[id->driver_data]); + return 0; +} + +static struct pci_device_id it8212_pci_tbl[] = { + { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, it8212_pci_tbl); + +static struct pci_driver driver = { + .name = "ITE8212 IDE", + .id_table = it8212_pci_tbl, + .probe = it8212_init_one, +}; + +static int __init it8212_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(it8212_ide_init); + +module_param_named(noraid, it8212_noraid, int, S_IRUGO); +MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode"); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for the ITE 8212"); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/Makefile linux-2.6.9/drivers/ide/pci/Makefile --- linux.vanilla-2.6.9/drivers/ide/pci/Makefile 2004-10-20 22:32:49.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/Makefile 2004-11-15 23:35:49.000000000 +0000 @@ -9,10 +9,12 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o +obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o #obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o +obj-$(CONFIG_BLK_DEV_IT8212) += it8212.o obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/pdc202xx_old.c linux-2.6.9/drivers/ide/pci/pdc202xx_old.c --- linux.vanilla-2.6.9/drivers/ide/pci/pdc202xx_old.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/pdc202xx_old.c 2004-12-11 00:10:18.000000000 +0000 @@ -347,7 +347,7 @@ { u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10); pci_read_config_word(hwif->pci_dev, 0x50, &CIS); - return ((u8)(CIS & mask)); + return (CIS & mask) ? 1 : 0; } /* @@ -709,7 +709,8 @@ struct pci_dev *dev = hwif->pci_dev; /* PDC20265 has problems with large LBA48 requests */ - if (dev->device == PCI_DEVICE_ID_PROMISE_20265) + if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) || + (dev->device == PCI_DEVICE_ID_PROMISE_20265)) hwif->rqsize = 256; hwif->autodma = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/serverworks.c linux-2.6.9/drivers/ide/pci/serverworks.c --- linux.vanilla-2.6.9/drivers/ide/pci/serverworks.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/serverworks.c 2004-12-01 17:14:08.000000000 +0000 @@ -539,11 +539,9 @@ else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { -// u32 pioreg = 0, dmareg = 0; /* Third Channel Test */ if (!(PCI_FUNC(dev->devfn) & 1)) { -#if 1 struct pci_dev * findev = NULL; u32 reg4c = 0; findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, @@ -555,19 +553,11 @@ reg4c |= 0x00000020; pci_write_config_dword(findev, 0x4C, reg4c); } -#endif outb_p(0x06, 0x0c00); dev->irq = inb_p(0x0c01); #if 0 - /* WE need to figure out how to get the correct one */ - printk("%s: interrupt %d\n", name, dev->irq); - if (dev->irq != 0x0B) - dev->irq = 0x0B; -#endif -#if 0 printk("%s: device class (0x%04x)\n", name, dev->class); -#else if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { dev->class &= ~0x000F0F00; // dev->class |= ~0x00000400; @@ -593,7 +583,8 @@ * interrupt pin to be set, and it is a compatibility * mode issue. */ - dev->irq = 0; + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) + dev->irq = 0; } // pci_read_config_dword(dev, 0x40, &pioreg) // pci_write_config_dword(dev, 0x40, 0x99999999); @@ -767,9 +758,6 @@ d->bootable = NEVER_BOARD; if (dev->resource[0].start == 0x01f1) d->bootable = ON_BOARD; - } else { - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) - return; } #if 0 if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) && @@ -815,10 +803,6 @@ .name = "Serverworks_IDE", .id_table = svwks_pci_tbl, .probe = svwks_init_one, -#if 0 /* FIXME: implement */ - .suspend = , - .resume = , -#endif }; static int svwks_ide_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/siimage.c linux-2.6.9/drivers/ide/pci/siimage.c --- linux.vanilla-2.6.9/drivers/ide/pci/siimage.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/siimage.c 2004-11-02 17:34:16.000000000 +0000 @@ -988,6 +988,21 @@ } /** + * siimage_fixup - post probe fixups + * @hwif: interface to fix up + * + * Called after drive probe we use this to decide whether the + * Seagate fixup must be applied. This used otbe in init_iops but + * that can occur before we know what drives are present. + */ + +static void siimage_fixup(ide_hwif_t *hwif) { + /* Try and raise the rqsize */ + if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0])) + hwif->rqsize = 128; +} + +/** * init_iops_siimage - set up iops * @hwif: interface to set up * @@ -1007,9 +1022,8 @@ hwif->hwif_data = NULL; - hwif->rqsize = 128; - if (is_sata(hwif) && is_dev_seagate_sata(&hwif->drives[0])) - hwif->rqsize = 15; + /* Pessimal until we finish probing */ + hwif->rqsize = 15; if (pci_get_drvdata(dev) == NULL) return; @@ -1101,6 +1115,7 @@ .channels = 2, \ .autodma = AUTODMA, \ .bootable = ON_BOARD, \ + .fixup = siimage_fixup \ } static ide_pci_device_t siimage_chipsets[] __devinitdata = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/pci/trm290.c linux-2.6.9/drivers/ide/pci/trm290.c --- linux.vanilla-2.6.9/drivers/ide/pci/trm290.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/ide/pci/trm290.c 2004-10-17 00:52:20.000000000 +0100 @@ -311,6 +311,7 @@ u8 reg = 0; struct pci_dev *dev = hwif->pci_dev; + /* FIXME: does this device support PIO LBA48 ? */ hwif->no_lba48 = 1; hwif->chipset = ide_trm290; cfgbase = pci_resource_start(dev, 4); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/ide/setup-pci.c linux-2.6.9/drivers/ide/setup-pci.c --- linux.vanilla-2.6.9/drivers/ide/setup-pci.c 2004-10-20 22:32:48.000000000 +0100 +++ linux-2.6.9/drivers/ide/setup-pci.c 2004-11-04 12:46:48.000000000 +0000 @@ -1,7 +1,8 @@ /* - * linux/drivers/ide/setup-pci.c Version 1.10 2002/08/19 + * linux/drivers/ide/setup-pci.c Version 1.14 2004/08/10 * * Copyright (c) 1998-2000 Andre Hedrick + * Copyright (c) 2004 Red Hat * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -11,6 +12,7 @@ * Use pci_set_master * Fix misreporting of I/O v MMIO problems * Initial fixups for simplex devices + * Hot unplug paths */ /* @@ -42,7 +44,7 @@ * Match a PCI IDE port against an entry in ide_hwifs[], * based on io_base port if possible. Return the matching hwif, * or a new hwif. If we find an error (clashing, out of devices, etc) - * return NULL + * return NULL. The caller must hold the ide_cfg_sem. * * FIXME: we need to handle mmio matches here too */ @@ -87,6 +89,8 @@ * * Unless there is a bootable card that does not use the standard * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag. + * + * FIXME: migrate use of ide_unknown to also use ->configured */ if (bootable) { for (h = 0; h < MAX_HWIFS; ++h) { @@ -435,8 +439,18 @@ ctl = port ? 0x374 : 0x3f4; base = port ? 0x170 : 0x1f0; } + + /* + * Protect against a hwif being unloaded as we attach to it + */ + down(&ide_cfg_sem); + if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL) + { + up(&ide_cfg_sem); return NULL; /* no room in ide_hwifs[] */ + } + if (hwif->io_ports[IDE_DATA_OFFSET] != base || hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) { memset(&hwif->hw, 0, sizeof(hwif->hw)); @@ -448,6 +462,9 @@ hwif->pci_dev = dev; hwif->cds = (struct ide_pci_device_s *) d; hwif->channel = port; + hwif->configured = 1; + + up(&ide_cfg_sem); if (!hwif->irq) hwif->irq = irq; @@ -729,14 +746,26 @@ return index; } +/** + * probe_pci_hwif_init - probe the hwif then allow fixups + * @hwif: interface to probe + * @d: PCI device + * + * Perform the generic probe and if it is successful invoke any + * remaining post probe fixup logic in the driver itself. + */ +static void probe_pci_hwif_init(ide_hwif_t *hwif, ide_pci_device_t *d) { + probe_hwif_init_with_fixup(hwif, d->fixup); +} + void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d) { ata_index_t index_list = do_ide_setup_pci_device(dev, d, 1); if ((index_list.b.low & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list.b.low]); + probe_pci_hwif_init(&ide_hwifs[index_list.b.low], d); if ((index_list.b.high & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list.b.high]); + probe_pci_hwif_init(&ide_hwifs[index_list.b.high], d); create_proc_ide_interfaces(); } @@ -749,19 +778,66 @@ ata_index_t index_list2 = do_ide_setup_pci_device(dev2, d, 0); if ((index_list.b.low & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list.b.low]); + probe_pci_hwif_init(&ide_hwifs[index_list.b.low], d); if ((index_list.b.high & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list.b.high]); + probe_pci_hwif_init(&ide_hwifs[index_list.b.high], d); if ((index_list2.b.low & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list2.b.low]); + probe_pci_hwif_init(&ide_hwifs[index_list2.b.low], d); if ((index_list2.b.high & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list2.b.high]); + probe_pci_hwif_init(&ide_hwifs[index_list2.b.high], d); create_proc_ide_interfaces(); } EXPORT_SYMBOL_GPL(ide_setup_pci_devices); +/** + * ide_pci_remove_hwifs - remove PCI interfaces + * @dev: PCI device + * + * Remove any hwif attached to this PCI device. This will call + * back the various hwif->remove functions. In order to get the + * best results when delays occur we kill the iops before we + * potentially start blocking for long periods untangling the + * IDE layer. + * + * Takes the ide_cfg_sem in order to protect against races with + * new/old hwifs. Calls functions that take all the other locks + * so should be called with no locks held. + */ + +void ide_pci_remove_hwifs(struct pci_dev *dev) +{ + int i; + ide_hwif_t *hwif = ide_hwifs; + + down(&ide_cfg_sem); +#if 0 + for(i = 0; i < MAX_HWIFS; i++) + { + if(hwif->configured && hwif->pci_dev == dev) + { + removed_hwif_iops(hwif); + } + i++; + hwif++; + } +#endif + hwif = ide_hwifs; + + for(i = 0; i < MAX_HWIFS; i++) + { + if(hwif->configured && hwif->pci_dev == dev) + __ide_unregister_hwif(hwif); + i++; + hwif++; + } + up(&ide_cfg_sem); +} + +EXPORT_SYMBOL_GPL(ide_pci_remove_hwifs); + + /* * Module interfaces */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/input/keyboard/atkbd.c linux-2.6.9/drivers/input/keyboard/atkbd.c --- linux.vanilla-2.6.9/drivers/input/keyboard/atkbd.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/input/keyboard/atkbd.c 2004-11-19 16:23:08.000000000 +0000 @@ -365,9 +365,13 @@ break; case ATKBD_KEY_UNKNOWN: if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { +#if 0 +/* Quite a few key switchers and other tools trigger this and it confuses + people who can do nothing about it */ printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " "like XFree86, might be trying access hardware directly.\n", data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); +#endif } else { printk(KERN_WARNING "atkbd.c: Unknown key %s " "(%s set %d, code %#x on %s).\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/input/serio/i8042.c linux-2.6.9/drivers/input/serio/i8042.c --- linux.vanilla-2.6.9/drivers/input/serio/i8042.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/input/serio/i8042.c 2004-10-21 18:00:55.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -666,6 +667,69 @@ } +static int i8042_spank_usb(void) +{ + struct pci_dev *usb = NULL; + int found = 0; + u16 word; + unsigned long addr; + unsigned long len; + int i; + + while((usb = pci_find_class((PCI_CLASS_SERIAL_USB << 8), usb)) != NULL) + { + /* UHCI controller not in legacy ? */ + + pci_read_config_word(usb, 0xC0, &word); + if(word & 0x2000) + continue; + + /* Check it is enabled. If the port is active in legacy mode + then this will be mapped already */ + + for(i = 0; i < PCI_ROM_RESOURCE; i++) + { + if (!(pci_resource_flags (usb, i) & IORESOURCE_IO)) + continue; + } + if(i == PCI_ROM_RESOURCE) + continue; + + /* + * Retrieve the bits + */ + + addr = pci_resource_start(usb, i); + len = pci_resource_len (usb, i); + + /* + * Check its configured and not in use + */ + if(addr == 0) + continue; + if (request_region(addr, len, "usb whackamole")) + continue; + + /* + * Kick the problem controller out of legacy mode + * so things like the E750x don't break + */ + + outw(0, addr + 4); /* IRQ Mask */ + outw(4, addr); /* Reset */ + msleep(20); + outw(0, addr); + + msleep(20); + /* Now take if off the BIOS */ + pci_write_config_word(usb, 0xC0, 0x2000); + release_region(addr, len); + + found = 1; + } + return found; +} + /* * i8042_controller init initializes the i8042 controller, and, * most importantly, sets it into non-xlated mode if that's @@ -674,6 +738,7 @@ static int i8042_controller_init(void) { + int tries = 0; unsigned long flags; /* @@ -703,9 +768,15 @@ * Save the CTR for restoral on unload / reboot. */ - if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { - printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); - return -1; + while(i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { + if(tries > 3 || !i8042_spank_usb()) + { + printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); + return -1; + } + printk(KERN_WARNING "i8042.c: Can't read CTR, disabling USB legacy and retrying.\n"); + i8042_flush(); + tries++; } i8042_initial_ctr = i8042_ctr; @@ -887,6 +958,40 @@ 0 }; +static int blink_frequency = 500; +module_param_named(panicblink, blink_frequency, int, 0600); + +#define DELAY mdelay(1), delay++ + +/* Tell the user who may be running in X and not see the console that we have + panic'ed. This is to distingush panics from "real" lockups. */ +static long i8042_panic_blink(long count) +{ + long delay = 0; + static long last_blink; + static char led; + /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is + different. */ + if (!blink_frequency) + return 0; + if (count - last_blink < blink_frequency) + return 0; + led ^= 0x01 | 0x04; + while (i8042_read_status() & I8042_STR_IBF) + DELAY; + i8042_write_data(0xed); /* set leds */ + DELAY; + while (i8042_read_status() & I8042_STR_IBF) + DELAY; + DELAY; + i8042_write_data(led); + DELAY; + last_blink = count; + return delay; +} + +#undef DELAY + /* * Suspend/resume handlers for the new PM scheme (driver model) */ @@ -1047,6 +1152,8 @@ register_reboot_notifier(&i8042_notifier); + panic_blink = i8042_panic_blink; + return 0; } @@ -1077,6 +1184,8 @@ driver_unregister(&i8042_driver); i8042_platform_exit(); + + panic_blink = NULL; } module_init(i8042_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/macintosh/mediabay.c linux-2.6.9/drivers/macintosh/mediabay.c --- linux.vanilla-2.6.9/drivers/macintosh/mediabay.c 2004-10-20 22:33:10.000000000 +0100 +++ linux-2.6.9/drivers/macintosh/mediabay.c 2004-11-13 00:02:14.000000000 +0000 @@ -82,6 +82,7 @@ #ifdef CONFIG_BLK_DEV_IDE unsigned long cd_base; int cd_index; + ide_hwif_t *cd_hwif; int cd_irq; int cd_retry; #endif @@ -569,7 +570,7 @@ ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL); hw.irq = bay->cd_irq; hw.chipset = ide_pmac; - bay->cd_index = ide_register_hw(&hw, NULL); + bay->cd_index = ide_register_hw(&hw, &bay->cd_hwif); pmu_resume(); } if (bay->cd_index == -1) { @@ -600,7 +601,7 @@ if (bay->cd_index >= 0) { printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); - ide_unregister(bay->cd_index); + ide_unregister_hwif(bay->cd_hwif); bay->cd_index = -1; } if (bay->cd_retry) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/dm-io.c linux-2.6.9/drivers/md/dm-io.c --- linux.vanilla-2.6.9/drivers/md/dm-io.c 2004-10-20 22:32:40.000000000 +0100 +++ linux-2.6.9/drivers/md/dm-io.c 2004-11-11 16:37:03.000000000 +0000 @@ -267,7 +267,7 @@ /* create new pool */ _io_pool = mempool_create(new_ios, alloc_io, free_io, NULL); if (!_io_pool) - r = -ENOMEM; + return -ENOMEM; r = bio_set_init(&_bios, "dm-io", 512, 1); if (r) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/dm-target.c linux-2.6.9/drivers/md/dm-target.c --- linux.vanilla-2.6.9/drivers/md/dm-target.c 2004-10-20 22:32:40.000000000 +0100 +++ linux-2.6.9/drivers/md/dm-target.c 2004-11-11 16:38:34.000000000 +0000 @@ -120,10 +120,9 @@ return -ENOMEM; down_write(&_lock); - if (__find_target_type(t->name)) { - kfree(ti); + if (__find_target_type(t->name)) rv = -EEXIST; - } else + else list_add(&ti->list, &_targets); up_write(&_lock); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/linear.c linux-2.6.9/drivers/md/linear.c --- linux.vanilla-2.6.9/drivers/md/linear.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/md/linear.c 2004-11-25 21:27:28.000000000 +0000 @@ -119,7 +119,8 @@ linear_conf_t *conf; struct linear_hash *table; mdk_rdev_t *rdev; - int size, i, nb_zone, cnt; + int i, nb_zone, cnt; + sector_t size; unsigned int curr_offset; struct list_head *tmp; @@ -268,10 +269,11 @@ char b[BDEVNAME_SIZE]; printk("linear_make_request: Block %llu out of bounds on " - "dev %s size %ld offset %ld\n", + "dev %s size %llu offset %llu\n", (unsigned long long)block, bdevname(tmp_dev->rdev->bdev, b), - tmp_dev->size, tmp_dev->offset); + (unsigned long long)tmp_dev->size, + (unsigned long long)tmp_dev->offset); bio_io_error(bio, bio->bi_size); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/multipath.c linux-2.6.9/drivers/md/multipath.c --- linux.vanilla-2.6.9/drivers/md/multipath.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/md/multipath.c 2004-12-01 21:02:38.000000000 +0000 @@ -155,7 +155,7 @@ r_queue->unplug_fn(r_queue); spin_lock_irqsave(&conf->device_lock, flags); - atomic_dec(&rdev->nr_pending); + rdev_dec_pending(rdev, mddev); } } spin_unlock_irqrestore(&conf->device_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/raid10.c linux-2.6.9/drivers/md/raid10.c --- linux.vanilla-2.6.9/drivers/md/raid10.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/md/raid10.c 2004-12-10 22:17:16.000000000 +0000 @@ -594,7 +594,7 @@ r_queue->unplug_fn(r_queue); spin_lock_irqsave(&conf->device_lock, flags); - atomic_dec(&rdev->nr_pending); + rdev_dec_pending(rdev, mddev); } } spin_unlock_irqrestore(&conf->device_lock, flags); @@ -1233,8 +1233,8 @@ int mirror; bio = r10_bio->devs[r10_bio->read_slot].bio; r10_bio->devs[r10_bio->read_slot].bio = NULL; + bio_put(bio); mirror = read_balance(conf, r10_bio); - r10_bio->devs[r10_bio->read_slot].bio = bio; if (mirror == -1) { printk(KERN_ALERT "raid10: %s: unrecoverable I/O" " read error for block %llu\n", @@ -1248,15 +1248,14 @@ " another mirror\n", bdevname(rdev->bdev,b), (unsigned long long)r10_bio->sector); - bio->bi_bdev = rdev->bdev; + bio = bio_clone(r10_bio->master_bio, GFP_NOIO); + r10_bio->devs[r10_bio->read_slot].bio = bio; bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr + rdev->data_offset; - bio->bi_next = NULL; - bio->bi_flags &= (1<bi_flags |= 1 << BIO_UPTODATE; - bio->bi_idx = 0; - bio->bi_size = r10_bio->sectors << 9; + bio->bi_bdev = rdev->bdev; bio->bi_rw = READ; + bio->bi_private = r10_bio; + bio->bi_end_io = raid10_end_read_request; unplug = 1; generic_make_request(bio); } @@ -1493,7 +1492,7 @@ for (i=0; icopies; i++) { int d = r10_bio->devs[i].devnum; if (r10_bio->devs[i].bio->bi_end_io) - atomic_dec(&conf->mirrors[d].rdev->nr_pending); + rdev_dec_pending(conf->mirrors[d].rdev, mddev); } put_buf(r10_bio); goto giveup; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/raid1.c linux-2.6.9/drivers/md/raid1.c --- linux.vanilla-2.6.9/drivers/md/raid1.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/md/raid1.c 2004-12-01 21:02:38.000000000 +0000 @@ -441,7 +441,7 @@ r_queue->unplug_fn(r_queue); spin_lock_irqsave(&conf->device_lock, flags); - atomic_dec(&rdev->nr_pending); + rdev_dec_pending(rdev, mddev); } } spin_unlock_irqrestore(&conf->device_lock, flags); @@ -941,6 +941,8 @@ } else { r1_bio->bios[r1_bio->read_disk] = NULL; r1_bio->read_disk = disk; + bio_put(bio); + bio = bio_clone(r1_bio->master_bio, GFP_NOIO); r1_bio->bios[r1_bio->read_disk] = bio; rdev = conf->mirrors[disk].rdev; if (printk_ratelimit()) @@ -948,9 +950,11 @@ " another mirror\n", bdevname(rdev->bdev,b), (unsigned long long)r1_bio->sector); - bio->bi_bdev = rdev->bdev; bio->bi_sector = r1_bio->sector + rdev->data_offset; + bio->bi_bdev = rdev->bdev; + bio->bi_end_io = raid1_end_read_request; bio->bi_rw = READ; + bio->bi_private = r1_bio; unplug = 1; generic_make_request(bio); } @@ -1087,7 +1091,7 @@ int rv = max_sector - sector_nr; md_done_sync(mddev, rv, 1); put_buf(r1_bio); - atomic_dec(&conf->mirrors[disk].rdev->nr_pending); + rdev_dec_pending(conf->mirrors[disk].rdev, mddev); return rv; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/raid5.c linux-2.6.9/drivers/md/raid5.c --- linux.vanilla-2.6.9/drivers/md/raid5.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/md/raid5.c 2004-12-01 21:02:38.000000000 +0000 @@ -1317,7 +1317,7 @@ r_queue->unplug_fn(r_queue); spin_lock_irqsave(&conf->device_lock, flags); - atomic_dec(&rdev->nr_pending); + rdev_dec_pending(rdev, mddev); } } spin_unlock_irqrestore(&conf->device_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/md/raid6main.c linux-2.6.9/drivers/md/raid6main.c --- linux.vanilla-2.6.9/drivers/md/raid6main.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/md/raid6main.c 2004-12-01 21:02:38.000000000 +0000 @@ -1479,7 +1479,7 @@ r_queue->unplug_fn(r_queue); spin_lock_irqsave(&conf->device_lock, flags); - atomic_dec(&rdev->nr_pending); + rdev_dec_pending(rdev, mddev); } } spin_unlock_irqrestore(&conf->device_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/media/video/cpia.c linux-2.6.9/drivers/media/video/cpia.c --- linux.vanilla-2.6.9/drivers/media/video/cpia.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/media/video/cpia.c 2004-11-17 20:10:06.000000000 +0000 @@ -4066,22 +4066,13 @@ proc_cpia_create(); #endif -#ifdef CONFIG_KMOD -#ifdef CONFIG_VIDEO_CPIA_PP_MODULE - request_module("cpia_pp"); -#endif - -#ifdef CONFIG_VIDEO_CPIA_USB_MODULE - request_module("cpia_usb"); -#endif -#endif /* CONFIG_KMOD */ - #ifdef CONFIG_VIDEO_CPIA_PP cpia_pp_init(); #endif #ifdef CONFIG_VIDEO_CPIA_USB cpia_usb_init(); #endif + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/media/video/zr36120.c linux-2.6.9/drivers/media/video/zr36120.c --- linux.vanilla-2.6.9/drivers/media/video/zr36120.c 2004-10-20 22:32:30.000000000 +0100 +++ linux-2.6.9/drivers/media/video/zr36120.c 2004-11-17 20:10:41.000000000 +0000 @@ -1474,7 +1474,7 @@ /* start mapping the whole shabang to user memory */ pos = (unsigned long)ztv->fbuffer; - while (size>0) { + while (size > 0) { unsigned long page = virt_to_phys((void*)pos); if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/3c59x.c linux-2.6.9/drivers/net/3c59x.c --- linux.vanilla-2.6.9/drivers/net/3c59x.c 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/net/3c59x.c 2004-11-25 20:53:55.000000000 +0000 @@ -416,7 +416,7 @@ HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800, EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000, - EXTRA_PREAMBLE=0x8000, }; + EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, }; enum vortex_chips { CH_3C590 = 0, @@ -491,9 +491,9 @@ {"3c595 Vortex 100base-MII", PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, {"3c900 Boomerang 10baseT", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, {"3c900 Boomerang 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps Combo", @@ -504,9 +504,9 @@ {"3c900B-FL Cyclone 10base-FL", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c905 Boomerang 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, {"3c905 Boomerang 100baseT4", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, {"3c905B Cyclone 100baseTx", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, @@ -3169,7 +3169,8 @@ pci_restore_state(VORTEX_PCI(vp), vp->power_state); } /* Should really use issue_and_wait() here */ - outw(TotalReset|0x14, dev->base_addr + EL3_CMD); + outw(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14), + dev->base_addr + EL3_CMD); pci_free_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/forcedeth.c linux-2.6.9/drivers/net/forcedeth.c --- linux.vanilla-2.6.9/drivers/net/forcedeth.c 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/net/forcedeth.c 2004-11-25 21:02:47.000000000 +0000 @@ -76,6 +76,9 @@ * for registers, link status and other minor fixes. * 0.28: 21 Jun 2004: Big cleanup, making driver mostly endian safe * 0.29: 31 Aug 2004: Add backup timer for link change notification. + * 0.30: 25 Sep 2004: rx checksum support for nf 250 Gb. Add rx reset + * into nv_close, otherwise reenabling for wol can + * cause DMA to kfree'd memory. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -87,7 +90,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.29" +#define FORCEDETH_VERSION "0.30" #define DRV_NAME "forcedeth" #include @@ -217,6 +220,7 @@ #define NVREG_TXRXCTL_BIT2 0x0004 #define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_RESET 0x0010 +#define NVREG_TXRXCTL_RXCHECK 0x0400 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -313,6 +317,10 @@ #define NV_RX_ERROR (1<<30) #define NV_RX_AVAIL (1<<31) +#define NV_RX2_CHECKSUMMASK (0x1C000000) +#define NV_RX2_CHECKSUMOK1 (0x10000000) +#define NV_RX2_CHECKSUMOK2 (0x14000000) +#define NV_RX2_CHECKSUMOK3 (0x18000000) #define NV_RX2_DESCRIPTORVALID (1<<29) #define NV_RX2_SUBSTRACT1 (1<<25) #define NV_RX2_ERROR1 (1<<18) @@ -371,8 +379,15 @@ #define POLL_WAIT (1+HZ/100) #define LINK_TIMEOUT (3*HZ) +/* + * desc_ver values: + * This field has two purposes: + * - Newer nics uses a different ring layout. The layout is selected by + * comparing np->desc_ver with DESC_VER_xy. + * - It contains bits that are forced on when writing to NvRegTxRxControl. + */ #define DESC_VER_1 0x0 -#define DESC_VER_2 0x02100 +#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) /* PHY defines */ #define PHY_OUI_MARVELL 0x5043 @@ -1181,6 +1196,15 @@ goto next_pkt; } } + Flags &= NV_RX2_CHECKSUMMASK; + if (Flags == NV_RX2_CHECKSUMOK1 || + Flags == NV_RX2_CHECKSUMOK2 || + Flags == NV_RX2_CHECKSUMOK3) { + dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name); + np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY; + } else { + dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name); + } } /* got a valid packet - forward it to the network core */ skb = np->rx_skbuff[i]; @@ -1673,9 +1697,10 @@ spin_lock_irq(&np->lock); nv_stop_tx(dev); nv_stop_rx(dev); - base = get_hwbase(dev); + nv_txrx_reset(dev); /* disable interrupts on the nic or we will lock up */ + base = get_hwbase(dev); writel(0, base + NvRegIrqMask); pci_push(base); dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/Kconfig linux-2.6.9/drivers/net/Kconfig --- linux.vanilla-2.6.9/drivers/net/Kconfig 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/net/Kconfig 2004-10-16 22:15:48.000000000 +0100 @@ -1742,18 +1742,6 @@ If unsure, say Y. -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. - - To compile this driver as a module, choose M here. The module - will be called via-velocity. - config LAN_SAA9730 bool "Philips SAA9730 Ethernet support (EXPERIMENTAL)" depends on NET_PCI && EXPERIMENTAL && MIPS @@ -2140,6 +2128,18 @@ say M here and read Documentation/kbuild/modules.txt. The module will be called sk98lin. This is recommended. +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. + + To compile this driver as a module, choose M here. The module + will be called via-velocity. + config TIGON3 tristate "Broadcom Tigon3 support" depends on PCI diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/pcmcia/smc91c92_cs.c linux-2.6.9/drivers/net/pcmcia/smc91c92_cs.c --- linux.vanilla-2.6.9/drivers/net/pcmcia/smc91c92_cs.c 2004-10-20 22:32:34.000000000 +0100 +++ linux-2.6.9/drivers/net/pcmcia/smc91c92_cs.c 2004-11-25 23:09:19.000000000 +0000 @@ -2113,7 +2113,7 @@ tmp |= TCR_FDUPLX; else tmp &= ~TCR_FDUPLX; - outw(ioaddr + TCR, tmp); + outw(tmp, ioaddr + TCR); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/ppp_async.c linux-2.6.9/drivers/net/ppp_async.c --- linux.vanilla-2.6.9/drivers/net/ppp_async.c 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/net/ppp_async.c 2004-10-21 22:25:16.000000000 +0100 @@ -238,6 +238,18 @@ } /* + * Called on tty hangup in process context. + * + * Wait for I/O to driver to complete and unregister PPP channel. + * This is already done by the close routine, so just call that. + */ +static int ppp_asynctty_hangup(struct tty_struct *tty) +{ + ppp_asynctty_close(tty); + return 0; +} + +/* * Read does nothing - no data is ever available this way. * Pppd reads and writes packets via /dev/ppp instead. */ @@ -380,6 +392,7 @@ .name = "ppp", .open = ppp_asynctty_open, .close = ppp_asynctty_close, + .hangup = ppp_asynctty_hangup, .read = ppp_asynctty_read, .write = ppp_asynctty_write, .ioctl = ppp_asynctty_ioctl, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/ppp_generic.c linux-2.6.9/drivers/net/ppp_generic.c --- linux.vanilla-2.6.9/drivers/net/ppp_generic.c 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/net/ppp_generic.c 2004-11-25 23:02:30.000000000 +0000 @@ -19,7 +19,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20020217== + * ==FILEVERSION 20041108== */ #include @@ -412,6 +412,17 @@ ret = 0; if (pf->dead) break; + if (pf->kind == INTERFACE) { + /* + * Return 0 (EOF) on an interface that has no + * channels connected, unless it is looping + * network traffic (demand mode). + */ + struct ppp *ppp = PF_TO_PPP(pf); + if (ppp->n_channels == 0 + && (ppp->flags & SC_LOOP_TRAFFIC) == 0) + break; + } ret = -EAGAIN; if (file->f_flags & O_NONBLOCK) break; @@ -491,6 +502,14 @@ mask |= POLLIN | POLLRDNORM; if (pf->dead) mask |= POLLHUP; + else if (pf->kind == INTERFACE) { + /* see comment in ppp_read */ + struct ppp *ppp = PF_TO_PPP(pf); + if (ppp->n_channels == 0 + && (ppp->flags & SC_LOOP_TRAFFIC) == 0) + mask |= POLLIN | POLLRDNORM; + } + return mask; } @@ -2559,7 +2578,8 @@ /* remove it from the ppp unit's list */ ppp_lock(ppp); list_del(&pch->clist); - --ppp->n_channels; + if (--ppp->n_channels == 0) + wake_up_interruptible(&ppp->file.rwait); ppp_unlock(ppp); if (atomic_dec_and_test(&ppp->file.refcnt)) ppp_destroy_interface(ppp); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/ppp_synctty.c linux-2.6.9/drivers/net/ppp_synctty.c --- linux.vanilla-2.6.9/drivers/net/ppp_synctty.c 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/net/ppp_synctty.c 2004-10-21 22:19:06.000000000 +0100 @@ -285,6 +285,18 @@ } /* + * Called on tty hangup in process context. + * + * Wait for I/O to driver to complete and unregister PPP channel. + * This is already done by the close routine, so just call that. + */ +static int ppp_sync_hangup(struct tty_struct *tty) +{ + ppp_sync_close(tty); + return 0; +} + +/* * Read does nothing - no data is ever available this way. * Pppd reads and writes packets via /dev/ppp instead. */ @@ -422,6 +434,7 @@ .name = "pppsync", .open = ppp_sync_open, .close = ppp_sync_close, + .hangup = ppp_sync_hangup, .read = ppp_sync_read, .write = ppp_sync_write, .ioctl = ppp_synctty_ioctl, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/net/via-rhine.c linux-2.6.9/drivers/net/via-rhine.c --- linux.vanilla-2.6.9/drivers/net/via-rhine.c 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/net/via-rhine.c 2004-12-01 21:04:12.000000000 +0000 @@ -627,7 +627,7 @@ } #ifdef USE_MMIO -static void __devinit enable_mmio(long pioaddr, u32 quirks) +static void enable_mmio(long pioaddr, u32 quirks) { int n; if (quirks & rqRhineI) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/parport/parport_pc.c linux-2.6.9/drivers/parport/parport_pc.c --- linux.vanilla-2.6.9/drivers/parport/parport_pc.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/parport/parport_pc.c 2004-10-21 22:23:50.000000000 +0100 @@ -1194,7 +1194,7 @@ #ifdef CONFIG_PARPORT_PC_SUPERIO /* Super-IO chipset detection, Winbond, SMSC */ -static int __devinit show_parconfig_smsc37c669(int io, int key) +static void __devinit show_parconfig_smsc37c669(int io, int key) { int cr1,cr4,cra,cr23,cr26,cr27,i=0; static const char *modes[]={ "SPP and Bidirectional (PS/2)", @@ -1261,26 +1261,17 @@ superios[i].io = 0x278; superios[i].irq = 5; } - if (io != superios[i].io) { - /* how many bytes? */ - if (!request_region(superios[i].io, 3, "smsc parport")) { - superios[i].io = 0; - return 0; - } - } d=(cr26 &0x0f); if((d==1) || (d==3)) superios[i].dma= d; else superios[i].dma= PARPORT_DMA_NONE; - return 1; } } - return 0; } -static int __devinit show_parconfig_winbond(int io, int key) +static void __devinit show_parconfig_winbond(int io, int key) { int cr30,cr60,cr61,cr70,cr74,crf0,i=0; static const char *modes[] = { @@ -1336,23 +1327,14 @@ printk(KERN_INFO "Super-IO: too many chips!\n"); else { superios[i].io = (cr60<<8)|cr61; - if (io != superios[i].io) { - /* how many bytes? */ - if (!request_region(superios[i].io, 3, "winbond parport")) { - superios[i].io = 0; - return 0; - } - } superios[i].irq = cr70&0x0f; superios[i].dma = (((cr74 & 0x07) > 3) ? PARPORT_DMA_NONE : (cr74 & 0x07)); - return 1; } } - return 0; } -static int __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid) +static void __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid) { const char *type = "unknown"; int id,progif=2; @@ -1360,7 +1342,7 @@ if (devid == devrev) /* simple heuristics, we happened to read some non-winbond register */ - return 0; + return; id=(devid<<8) | devrev; @@ -1385,20 +1367,19 @@ efer, key, devid, devrev, oldid, type); if (progif == 2) - return show_parconfig_winbond(efer,key); - return 0; + show_parconfig_winbond(efer,key); } -static int __devinit decode_smsc(int efer, int key, int devid, int devrev) +static void __devinit decode_smsc(int efer, int key, int devid, int devrev) { const char *type = "unknown"; - int (*func)(int io, int key); + void (*func)(int io, int key); int id; if (devid == devrev) /* simple heuristics, we happened to read some non-smsc register */ - return 0; + return; func=NULL; id=(devid<<8) | devrev; @@ -1414,8 +1395,7 @@ efer, key, devid, devrev, type); if (func) - return func(efer,key); - return 0; + func(efer,key); } @@ -1448,8 +1428,7 @@ if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) goto out; /* protection against false positives */ - if (decode_winbond(io,key,devid,devrev,oldid)); - return; + decode_winbond(io,key,devid,devrev,oldid); out: release_region(io, 3); } @@ -1482,8 +1461,7 @@ if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) goto out; /* protection against false positives */ - if (decode_winbond(io,key,devid,devrev,oldid)) - return; + decode_winbond(io,key,devid,devrev,oldid); out: release_region(io, 3); } @@ -1522,8 +1500,7 @@ (x_oldid == oldid) && (x_rev == rev)) goto out; /* protection against false positives */ - if (decode_smsc(io,key,oldid,oldrev)) - return; + decode_smsc(io,key,oldid,oldrev); out: release_region(io, 3); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/pci/probe.c linux-2.6.9/drivers/pci/probe.c --- linux.vanilla-2.6.9/drivers/pci/probe.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/pci/probe.c 2004-11-25 20:11:43.000000000 +0000 @@ -326,6 +326,16 @@ return child; } +static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) +{ + struct pci_bus *parent = child->parent; + while (parent->parent && parent->subordinate < max) { + parent->subordinate = max; + pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max); + parent = parent->parent; + } +} + unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); /* @@ -410,7 +420,13 @@ if (!is_cardbus) { child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA; - + /* + * Adjust subordinate busnr in parent buses. + * We do this before scanning for children because + * some devices may not be detected if the bios + * was lazy. + */ + pci_fixup_parent_subordinate_busnr(child, max); /* Now we can scan all subordinate buses... */ max = pci_scan_child_bus(child); } else { @@ -420,6 +436,7 @@ * inserted later. */ max += CARDBUS_RESERVE_BUSNR; + pci_fixup_parent_subordinate_busnr(child, max); } /* * Set the subordinate bus number to its real value. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/pci/quirks.c linux-2.6.9/drivers/pci/quirks.c --- linux.vanilla-2.6.9/drivers/pci/quirks.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/pci/quirks.c 2004-11-25 22:56:48.000000000 +0000 @@ -477,7 +477,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); -static void __devinit quirk_via_irqpic(struct pci_dev *dev) +static void quirk_via_irqpic(struct pci_dev *dev) { u8 irq, new_irq = dev->irq & 0xf; @@ -494,6 +494,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, quirk_via_irqpic ); /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/pcmcia/yenta_socket.c linux-2.6.9/drivers/pcmcia/yenta_socket.c --- linux.vanilla-2.6.9/drivers/pcmcia/yenta_socket.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/pcmcia/yenta_socket.c 2004-11-13 18:05:52.000000000 +0000 @@ -1092,6 +1092,7 @@ CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, 0x8036, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/pnp/pnpbios/bioscalls.c linux-2.6.9/drivers/pnp/pnpbios/bioscalls.c --- linux.vanilla-2.6.9/drivers/pnp/pnpbios/bioscalls.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/pnp/pnpbios/bioscalls.c 2004-11-15 16:06:58.000000000 +0000 @@ -165,7 +165,7 @@ if(pnp_bios_is_utter_crap) { printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n"); - printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably\n"); + printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n"); printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/pnp/pnpbios/core.c linux-2.6.9/drivers/pnp/pnpbios/core.c --- linux.vanilla-2.6.9/drivers/pnp/pnpbios/core.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/pnp/pnpbios/core.c 2004-11-25 20:16:57.000000000 +0000 @@ -538,6 +538,13 @@ return -ENODEV; } +#if defined(CONFIG_ACPI) + if (!acpi_disabled) { + pnpbios_disabled = 1; + printk(KERN_INFO "PnPBIOS: Disabled by ACPI\n"); + return -ENODEV; + } +#endif /* scan the system for pnpbios support */ if (!pnpbios_probe_system()) return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/3w-9xxx.c linux-2.6.9/drivers/scsi/3w-9xxx.c --- linux.vanilla-2.6.9/drivers/scsi/3w-9xxx.c 2004-10-20 22:32:53.000000000 +0100 +++ linux-2.6.9/drivers/scsi/3w-9xxx.c 2004-11-25 21:24:18.000000000 +0000 @@ -1746,6 +1746,7 @@ twa_free_request_id(tw_dev, request_id); SCpnt->result = (DID_ERROR << 16); done(SCpnt); + retval = 0; } return retval; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/aacraid/commsup.c linux-2.6.9/drivers/scsi/aacraid/commsup.c --- linux.vanilla-2.6.9/drivers/scsi/aacraid/commsup.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/scsi/aacraid/commsup.c 2004-12-10 20:28:37.000000000 +0000 @@ -781,6 +781,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) { struct hw_fib * hw_fib = fibptr->hw_fib; +#if 0 /* * Set the status of this FIB to be Invalid parameter. * @@ -788,6 +789,8 @@ */ *(u32 *)hw_fib->data = cpu_to_le32(ST_OK); fib_adapter_complete(fibptr, sizeof(u32)); + /* This will be done on our return */ +#endif } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic79xx_core.c linux-2.6.9/drivers/scsi/aic7xxx/aic79xx_core.c --- linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic79xx_core.c 2004-10-20 22:32:52.000000000 +0100 +++ linux-2.6.9/drivers/scsi/aic7xxx/aic79xx_core.c 2004-10-24 17:37:01.000000000 +0100 @@ -5270,7 +5270,6 @@ default: case 5: ahd_shutdown(ahd); - TAILQ_REMOVE(&ahd_tailq, ahd, links); /* FALLTHROUGH */ case 4: ahd_dmamap_unload(ahd, ahd->shared_data_dmat, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm.c linux-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm.c --- linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm.c 2004-11-25 20:54:28.000000000 +0000 @@ -851,6 +851,7 @@ { struct ahd_softc *ahd; int found; + int error = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* @@ -902,7 +903,9 @@ ahd_list_lockinit(); #ifdef CONFIG_PCI - ahd_linux_pci_init(); + error = ahd_linux_pci_init(); + if (error) + return error; #endif /* @@ -919,7 +922,7 @@ spin_lock_irq(&io_request_lock); #endif aic79xx_detect_complete++; - return (found); + return 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) @@ -5073,7 +5076,7 @@ ahd_linux_init(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - return (ahd_linux_detect(&aic79xx_driver_template) ? 0 : -ENODEV); + return ahd_linux_detect(&aic79xx_driver_template); #else scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template); if (aic79xx_driver_template.present == 0) { @@ -5090,7 +5093,6 @@ ahd_linux_exit(void) { struct ahd_softc *ahd; - u_long l; /* * Shutdown DV threads before going into the SCSI mid-layer. @@ -5098,12 +5100,11 @@ * kernel so that waiting for our DV threads to exit leads * to deadlock. */ - ahd_list_lock(&l); TAILQ_FOREACH(ahd, &ahd_tailq, links) { ahd_linux_kill_dv_thread(ahd); } - ahd_list_unlock(&l); + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * In 2.4 we have to unregister from the PCI core _after_ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm_pci.c linux-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm_pci.c --- linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2004-10-20 22:32:51.000000000 +0100 +++ linux-2.6.9/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2004-10-24 17:37:01.000000000 +0100 @@ -92,12 +92,14 @@ if (ahd != NULL) { u_long s; + TAILQ_REMOVE(&ahd_tailq, ahd, links); + ahd_list_unlock(&l); ahd_lock(ahd, &s); ahd_intr_enable(ahd, FALSE); ahd_unlock(ahd, &s); ahd_free(ahd); - } - ahd_list_unlock(&l); + } else + ahd_list_unlock(&l); } #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.6.9/drivers/scsi/aic7xxx/aic7xxx_core.c --- linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic7xxx_core.c 2004-10-20 22:32:51.000000000 +0100 +++ linux-2.6.9/drivers/scsi/aic7xxx/aic7xxx_core.c 2004-10-24 17:37:01.000000000 +0100 @@ -3973,7 +3973,6 @@ default: case 5: ahc_shutdown(ahc); - TAILQ_REMOVE(&ahc_tailq, ahc, links); /* FALLTHROUGH */ case 4: ahc_dmamap_unload(ahc, ahc->shared_data_dmat, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm.c --- linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm.c 2004-10-20 23:16:55.000000000 +0100 +++ linux-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm.c 2004-10-24 17:37:01.000000000 +0100 @@ -5098,7 +5098,6 @@ ahc_linux_exit(void) { struct ahc_softc *ahc; - u_long l; /* * Shutdown DV threads before going into the SCSI mid-layer. @@ -5106,12 +5105,10 @@ * kernel so that waiting for our DV threads to exit leads * to deadlock. */ - ahc_list_lock(&l); TAILQ_FOREACH(ahc, &ahc_tailq, links) { ahc_linux_kill_dv_thread(ahc); } - ahc_list_unlock(&l); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c linux-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c --- linux.vanilla-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c 2004-10-20 22:32:51.000000000 +0100 +++ linux-2.6.9/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c 2004-10-24 17:37:01.000000000 +0100 @@ -95,12 +95,14 @@ if (ahc != NULL) { u_long s; + TAILQ_REMOVE(&ahc_tailq, ahc, links); + ahc_list_unlock(&l); ahc_lock(ahc, &s); ahc_intr_enable(ahc, FALSE); ahc_unlock(ahc, &s); ahc_free(ahc); - } - ahc_list_unlock(&l); + } else + ahc_list_unlock(&l); } #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/ide-scsi.c linux-2.6.9/drivers/scsi/ide-scsi.c --- linux.vanilla-2.6.9/drivers/scsi/ide-scsi.c 2004-10-20 22:32:53.000000000 +0100 +++ linux-2.6.9/drivers/scsi/ide-scsi.c 2004-11-25 21:23:33.000000000 +0000 @@ -930,7 +930,7 @@ if (rq) kfree (rq); cmd->result = DID_ERROR << 16; done(cmd); - return 1; + return 0; } static int idescsi_eh_abort (Scsi_Cmnd *cmd) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/nsp32.h linux-2.6.9/drivers/scsi/nsp32.h --- linux.vanilla-2.6.9/drivers/scsi/nsp32.h 2004-10-20 22:32:54.000000000 +0100 +++ linux-2.6.9/drivers/scsi/nsp32.h 2004-10-24 17:32:00.000000000 +0100 @@ -22,7 +22,6 @@ * VENDOR/DEVICE ID */ #define PCI_VENDOR_ID_IODATA 0x10fc -#define PCI_VENDOR_ID_WORKBIT 0x1145 #define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II 0x0005 #define PCI_DEVICE_ID_NINJASCSI_32BI_KME 0xf007 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/scsi.c linux-2.6.9/drivers/scsi/scsi.c --- linux.vanilla-2.6.9/drivers/scsi/scsi.c 2004-10-20 23:16:56.000000000 +0100 +++ linux-2.6.9/drivers/scsi/scsi.c 2004-11-25 21:01:10.000000000 +0000 @@ -244,7 +244,13 @@ */ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) { - struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask); + struct scsi_cmnd *cmd; + + /* Bail if we can't get a reference to the device */ + if (!get_device(&dev->sdev_gendev)) + return NULL; + + cmd = __scsi_get_command(dev->host, gfp_mask); if (likely(cmd != NULL)) { unsigned long flags; @@ -258,7 +264,8 @@ spin_lock_irqsave(&dev->list_lock, flags); list_add_tail(&cmd->list, &dev->cmd_list); spin_unlock_irqrestore(&dev->list_lock, flags); - } + } else + put_device(&dev->sdev_gendev); return cmd; } @@ -276,7 +283,8 @@ */ void scsi_put_command(struct scsi_cmnd *cmd) { - struct Scsi_Host *shost = cmd->device->host; + struct scsi_device *sdev = cmd->device; + struct Scsi_Host *shost = sdev->host; unsigned long flags; /* serious error if the command hasn't come from a device list */ @@ -294,6 +302,8 @@ if (likely(cmd != NULL)) kmem_cache_free(shost->cmd_pool->slab, cmd); + + put_device(&sdev->sdev_gendev); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/scsi_lib.c linux-2.6.9/drivers/scsi/scsi_lib.c --- linux.vanilla-2.6.9/drivers/scsi/scsi_lib.c 2004-10-20 23:16:56.000000000 +0100 +++ linux-2.6.9/drivers/scsi/scsi_lib.c 2004-11-25 21:02:05.000000000 +0000 @@ -1585,11 +1585,12 @@ if (!sreq) return -ENOMEM; - sreq->sr_data_direction = DMA_NONE; - scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); + sreq->sr_data_direction = DMA_NONE; + scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && - (sreq->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION && + ((sreq->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION || + (sreq->sr_sense_buffer[2] & 0x0f) == NOT_READY) && sdev->removable) { sdev->changed = 1; sreq->sr_result = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/scsi/sg.c linux-2.6.9/drivers/scsi/sg.c --- linux.vanilla-2.6.9/drivers/scsi/sg.c 2004-10-20 23:16:56.000000000 +0100 +++ linux-2.6.9/drivers/scsi/sg.c 2004-11-25 21:30:18.000000000 +0000 @@ -576,6 +576,7 @@ sg_io_hdr_t *hp; unsigned char cmnd[sizeof (dummy_cmdp->sr_cmnd)]; int timeout; + unsigned long ul_timeout; if (count < SZ_SG_IO_HDR) return -EINVAL; @@ -610,7 +611,8 @@ return -EBUSY; /* reserve buffer already being used */ } } - timeout = msecs_to_jiffies(srp->header.timeout); + ul_timeout = msecs_to_jiffies(srp->header.timeout); + timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX; if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) { sg_remove_request(sfp, srp); return -EMSGSIZE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/host/ehci-sched.c linux-2.6.9/drivers/usb/host/ehci-sched.c --- linux.vanilla-2.6.9/drivers/usb/host/ehci-sched.c 2004-10-20 23:16:56.000000000 +0100 +++ linux-2.6.9/drivers/usb/host/ehci-sched.c 2004-11-15 16:06:16.000000000 +0000 @@ -907,6 +907,7 @@ if (unlikely (0 == itd)) { iso_sched_free (stream, sched); + spin_unlock_irqrestore (&ehci->lock, flags); return -ENOMEM; } memset (itd, 0, sizeof *itd); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/Kconfig linux-2.6.9/drivers/usb/media/Kconfig --- linux.vanilla-2.6.9/drivers/usb/media/Kconfig 2004-10-20 23:16:56.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/Kconfig 2004-11-15 23:35:48.000000000 +0000 @@ -175,3 +175,39 @@ To compile this driver as a module, choose M here: the module will be called w9968cf. + +config USB_PWC + tristate "USB Philips Cameras" + depends on USB && VIDEO_DEV + ---help--- + Say Y or M here if you want to use one of these Philips & OEM + webcams: + * Philips PCA645, PCA646 + * Philips PCVC675, PCVC680, PCVC690 + * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 + * Askey VC010 + * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' + and 'Orbit'/'Sphere' + * Samsung MPC-C10, MPC-C30 + * Creative Webcam 5, Pro Ex + * SOTEC Afina Eye + * Visionite VCS-UC300, VCS-UM100 + + The PCA635, PCVC665 and PCVC720/20 are not supported by this driver + and never will be, but the 665 and 720/20 are supported by other + drivers. + + See for more information and + installation instructions. + + The built-in microphone is enabled by selecting USB Audio support. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Character Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + at . + + To compile this driver as a module, choose M here: the + module will be called pwc. + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/Makefile linux-2.6.9/drivers/usb/media/Makefile --- linux.vanilla-2.6.9/drivers/usb/media/Makefile 2004-10-20 23:16:56.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/Makefile 2004-11-15 23:35:48.000000000 +0000 @@ -14,3 +14,4 @@ obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o +obj-$(CONFIG_USB_PWC) += pwc/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/ChangeLog linux-2.6.9/drivers/usb/media/pwc/ChangeLog --- linux.vanilla-2.6.9/drivers/usb/media/pwc/ChangeLog 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/ChangeLog 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,143 @@ +9.0.2 + +* Adding #ifdef to compile PWC before and after 2.6.5 + +9.0.1 + +9.0 + + +8.12 + +* Implement motorized pan/tilt feature for Logitech QuickCam Orbit/Spere. + +8.11.1 + +* Fix for PCVC720/40, would not be able to set videomode +* Fix for Samsung MPC models, appearantly they are based on a newer chipset + +8.11 + +* 20 dev_hints (per request) +* Hot unplugging should be better, no more dangling pointers or memory leaks +* Added reserved Logitech webcam IDs +* Device now remembers size & fps between close()/open() +* Removed palette stuff altogether + +8.10.1 + +* Added IDs for PCVC720K/40 and Creative Labs Webcam Pro + +8.10 + +* Fixed ID for QuickCam Notebook pro +* Added GREALSIZE ioctl() call +* Fixed bug in case PWCX was not loaded and invalid size was set + +8.9 + +* Merging with kernel 2.5.49 +* Adding IDs for QuickCam Zoom & QuickCam Notebook + +8.8 + +* Fixing 'leds' parameter +* Adding IDs for Logitech QuickCam Pro 4000 +* Making URB init/cleanup a little nicer + +8.7 + +* Incorporating changes in ioctl() parameter passing +* Also changes to URB mechanism + +8.6 + +* Added ID's for Visionite VCS UM100 and UC300 +* Removed YUV420-interlaced palette altogether (was confusing) +* Removed MIRROR stuff as it didn't work anyway +* Fixed a problem with the 'leds' parameter (wouldn't blink) +* Added ioctl()s for advanced features: 'extended' whitebalance ioctl()s, + CONTOUR, BACKLIGHT, FLICKER, DYNNOISE. +* VIDIOCGCAP.name now contains real camera model name instead of + 'Philips xxx webcam' +* Added PROBE ioctl (see previous point & API doc) + +8.5 + +* Adding IDs for Creative Labs Webcam 5 +* Adding IDs for SOTEC CMS-001 webcam +* Solving possible hang in VIDIOCSYNC when unplugging the cam +* Forgot to return structure in VIDIOCPWCGAWB, oops +* Time interval for the LEDs are now in milliseconds + +8.4 + +* Fixing power_save option for Vesta range +* Handling new error codes in ISOC callback +* Adding dev_hint module parameter, to specify /dev/videoX device nodes + +8.3 + +* Adding Samsung C10 and C30 cameras +* Removing palette module parameter +* Fixed typo in ID of QuickCam 3000 Pro +* Adding LED settings (blinking while in use) for ToUCam cameras. +* Turns LED off when camera is not in use. + +8.2 + +* Making module more silent when trace = 0 +* Adding QuickCam 3000 Pro IDs +* Chrominance control for the Vesta cameras +* Hopefully fixed problems on machines with BIGMEM and > 1GB of RAM +* Included Oliver Neukem's lock_kernel() patch +* Allocates less memory for image buffers +* Adds ioctl()s for the whitebalancing + +8.1 + +* Adding support for 750 +* Adding V4L GAUDIO/SAUDIO/UNIT ioctl() calls + +8.0 +* 'damage control' after inclusion in 2.4.5. +* Changed wait-queue mechanism in read/mmap/poll according to the book. +* Included YUV420P palette. +* Changed interface to decompressor module. +* Cleaned up pwc structure a bit. + +7.0 + +* Fixed bug in vcvt_420i_yuyv; extra variables on stack were misaligned. +* There is now a clear error message when an image size is selected that + is only supported using the decompressor, and the decompressor isn't + loaded. +* When the decompressor wasn't loaded, selecting large image size + would create skewed or double images. + +6.3 + +* Introduced spinlocks for the buffer pointer manipulation; a number of + reports seem to suggest the down()/up() semaphores were the cause of + lockups, since they are not suitable for interrupt/user locking. +* Separated decompressor and core code into 2 modules. + +6.2 + +* Non-integral image sizes are now padded with gray or black. +* Added SHUTTERSPEED ioctl(). +* Fixed buglet in VIDIOCPWCSAGC; the function would always return an error, + even though the call succeeded. +* Added hotplug support for 2.4.*. +* Memory: the 645/646 uses less memory now. + +6.1 + +* VIDIOCSPICT returns -EINVAL with invalid palettes. +* Added saturation control. +* Split decompressors from rest. +* Fixed bug that would reset the framerate to the default framerate if + the rate field was set to 0 (which is not what I intended, nl. do not + change the framerate!). +* VIDIOCPWCSCQUAL (setting compression quality) now takes effect immediately. +* Workaround for a bug in the 730 sensor. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/Makefile linux-2.6.9/drivers/usb/media/pwc/Makefile --- linux.vanilla-2.6.9/drivers/usb/media/pwc/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/Makefile 2004-11-15 23:35:48.000000000 +0000 @@ -0,0 +1,20 @@ +ifneq ($(KERNELRELEASE),) + +pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o + +obj-m += pwc.o + +else + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +default: + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules + +endif + +clean: + rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c + rm -rf .tmp_versions + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-ctrl.c linux-2.6.9/drivers/usb/media/pwc/pwc-ctrl.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-ctrl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-ctrl.c 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,1630 @@ +/* Driver for Philips webcam + Functions that send various control messages to the webcam, including + video modes. + (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + +/* + Changes + 2001/08/03 Alvarado Added methods for changing white balance and + red/green gains + */ + +/* Control functions for the cam; brightness, contrast, video mode, etc. */ + +#ifdef __KERNEL__ +#include +#endif +#include +#include + +#include "pwc.h" +#include "pwc-ioctl.h" +#include "pwc-uncompress.h" +#include "pwc-kiara.h" +#include "pwc-timon.h" +#include "pwc-dec1.h" +#include "pwc-dec23.h" + +/* Request types: video */ +#define SET_LUM_CTL 0x01 +#define GET_LUM_CTL 0x02 +#define SET_CHROM_CTL 0x03 +#define GET_CHROM_CTL 0x04 +#define SET_STATUS_CTL 0x05 +#define GET_STATUS_CTL 0x06 +#define SET_EP_STREAM_CTL 0x07 +#define GET_EP_STREAM_CTL 0x08 +#define SET_MPT_CTL 0x0D +#define GET_MPT_CTL 0x0E + +/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ +#define AGC_MODE_FORMATTER 0x2000 +#define PRESET_AGC_FORMATTER 0x2100 +#define SHUTTER_MODE_FORMATTER 0x2200 +#define PRESET_SHUTTER_FORMATTER 0x2300 +#define PRESET_CONTOUR_FORMATTER 0x2400 +#define AUTO_CONTOUR_FORMATTER 0x2500 +#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 +#define CONTRAST_FORMATTER 0x2700 +#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 +#define FLICKERLESS_MODE_FORMATTER 0x2900 +#define AE_CONTROL_SPEED 0x2A00 +#define BRIGHTNESS_FORMATTER 0x2B00 +#define GAMMA_FORMATTER 0x2C00 + +/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ +#define WB_MODE_FORMATTER 0x1000 +#define AWB_CONTROL_SPEED_FORMATTER 0x1100 +#define AWB_CONTROL_DELAY_FORMATTER 0x1200 +#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 +#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 +#define COLOUR_MODE_FORMATTER 0x1500 +#define SATURATION_MODE_FORMATTER1 0x1600 +#define SATURATION_MODE_FORMATTER2 0x1700 + +/* Selectors for the Status controls [GS]ET_STATUS_CTL */ +#define SAVE_USER_DEFAULTS_FORMATTER 0x0200 +#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 +#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 +#define READ_AGC_FORMATTER 0x0500 +#define READ_SHUTTER_FORMATTER 0x0600 +#define READ_RED_GAIN_FORMATTER 0x0700 +#define READ_BLUE_GAIN_FORMATTER 0x0800 +#define SENSOR_TYPE_FORMATTER1 0x0C00 +#define READ_RAW_Y_MEAN_FORMATTER 0x3100 +#define SET_POWER_SAVE_MODE_FORMATTER 0x3200 +#define MIRROR_IMAGE_FORMATTER 0x3300 +#define LED_FORMATTER 0x3400 +#define SENSOR_TYPE_FORMATTER2 0x3700 + +/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ +#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 + +/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ +#define PT_RELATIVE_CONTROL_FORMATTER 0x01 +#define PT_RESET_CONTROL_FORMATTER 0x02 +#define PT_STATUS_FORMATTER 0x03 + +static char *size2name[PSZ_MAX] = +{ + "subQCIF", + "QSIF", + "QCIF", + "SIF", + "CIF", + "VGA", +}; + +/********/ + +/* Entries for the Nala (645/646) camera; the Nala doesn't have compression + preferences, so you either get compressed or non-compressed streams. + + An alternate value of 0 means this mode is not available at all. + */ + +struct Nala_table_entry { + char alternate; /* USB alternate setting */ + int compressed; /* Compressed yes/no */ + + unsigned char mode[3]; /* precomputed mode table */ +}; + +static struct Nala_table_entry Nala_table[PSZ_MAX][8] = +{ +#include "pwc-nala.h" +}; + + +/****************************************************************************/ + + +#define SendControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) + +#define RecvControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) + + +#if PWC_DEBUG +void pwc_hexdump(void *p, int len) +{ + int i; + unsigned char *s; + char buf[100], *d; + + s = (unsigned char *)p; + d = buf; + *d = '\0'; + Debug("Doing hexdump @ %p, %d bytes.\n", p, len); + for (i = 0; i < len; i++) { + d += sprintf(d, "%02X ", *s++); + if ((i & 0xF) == 0xF) { + Debug("%s\n", buf); + d = buf; + *d = '\0'; + } + } + if ((i & 0xF) != 0) + Debug("%s\n", buf); +} +#endif + +static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) +{ + return usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + SET_EP_STREAM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + VIDEO_OUTPUT_CONTROL_FORMATTER, + index, + buf, buflen, HZ); +} + + + +static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) +{ + unsigned char buf[3]; + int ret, fps; + struct Nala_table_entry *pEntry; + int frames2frames[31] = + { /* closest match of framerate */ + 0, 0, 0, 0, 4, /* 0-4 */ + 5, 5, 7, 7, 10, /* 5-9 */ + 10, 10, 12, 12, 15, /* 10-14 */ + 15, 15, 15, 20, 20, /* 15-19 */ + 20, 20, 20, 24, 24, /* 20-24 */ + 24, 24, 24, 24, 24, /* 25-29 */ + 24 /* 30 */ + }; + int frames2table[31] = + { 0, 0, 0, 0, 0, /* 0-4 */ + 1, 1, 1, 2, 2, /* 5-9 */ + 3, 3, 4, 4, 4, /* 10-14 */ + 5, 5, 5, 5, 5, /* 15-19 */ + 6, 6, 6, 6, 7, /* 20-24 */ + 7, 7, 7, 7, 7, /* 25-29 */ + 7 /* 30 */ + }; + + if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) + return -EINVAL; + frames = frames2frames[frames]; + fps = frames2table[frames]; + pEntry = &Nala_table[size][fps]; + if (pEntry->alternate == 0) + return -EINVAL; + + if (pEntry->compressed) + return -ENOENT; /* Not supported. */ + + memcpy(buf, pEntry->mode, 3); + ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); + if (ret < 0) { + Debug("Failed to send video command... %d\n", ret); + return ret; + } + if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) + { + switch(pdev->type) { + case 645: + case 646: + pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); + break; + + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + break; + } + } + + pdev->cmd_len = 3; + memcpy(pdev->cmd_buf, buf, 3); + + /* Set various parameters */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->valternate = pEntry->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; + if (pEntry->compressed) { + if (pdev->release < 5) { /* 4 fold compression */ + pdev->vbandlength = 528; + pdev->frame_size /= 4; + } + else { + pdev->vbandlength = 704; + pdev->frame_size /= 3; + } + } + else + pdev->vbandlength = 0; + return 0; +} + + +static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +{ + unsigned char buf[13]; + const struct Timon_table_entry *pChoose; + int ret, fps; + + if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + return -EINVAL; + if (size == PSZ_VGA && frames > 15) + return -EINVAL; + fps = (frames / 5) - 1; + + /* Find a supported framerate with progressively higher compression ratios + if the preferred ratio is not available. + */ + pChoose = NULL; + while (compression <= 3) { + pChoose = &Timon_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; + } + if (pChoose == NULL || pChoose->alternate == 0) + return -ENOENT; /* Not supported. */ + + memcpy(buf, pChoose->mode, 13); + if (snapshot) + buf[0] |= 0x80; + ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); + if (ret < 0) + return ret; + + if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + + pdev->cmd_len = 13; + memcpy(pdev->cmd_buf, buf, 13); + + /* Set various parameters */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->vsnapshot = snapshot; + pdev->valternate = pChoose->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->vbandlength = pChoose->bandlength; + if (pChoose->bandlength > 0) + pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; + else + pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + return 0; +} + + +static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +{ + const struct Kiara_table_entry *pChoose = 0; + 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}}; + + if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + return -EINVAL; + if (size == PSZ_VGA && frames > 15) + return -EINVAL; + fps = (frames / 5) - 1; + + /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ + if (size == PSZ_VGA && frames == 5 && snapshot) + { + /* Only available in case the raw palette is selected or + we have the decompressor available. This mode is + only available in compressed form + */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); + pChoose = &RawEntry; + } + else + { + Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); + } + } + else + { + /* Find a supported framerate with progressively higher compression ratios + if the preferred ratio is not available. + Skip this step when using RAW modes. + */ + while (compression <= 3) { + pChoose = &Kiara_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; + } + } + if (pChoose == NULL || pChoose->alternate == 0) + return -ENOENT; /* Not supported. */ + + Debug("Using alternate setting %d.\n", pChoose->alternate); + + /* usb_control_msg won't take staticly allocated arrays as argument?? */ + memcpy(buf, pChoose->mode, 12); + if (snapshot) + buf[0] |= 0x80; + + /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ + ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); + if (ret < 0) + return ret; + + if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + + pdev->cmd_len = 12; + memcpy(pdev->cmd_buf, buf, 12); + /* All set and go */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->vsnapshot = snapshot; + pdev->valternate = pChoose->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->vbandlength = pChoose->bandlength; + if (pdev->vbandlength > 0) + pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; + else + pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + return 0; +} + + + +/** + @pdev: device structure + @width: viewport width + @height: viewport height + @frame: framerate, in fps + @compression: preferred compression ratio + @snapshot: snapshot mode or streaming + */ +int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) +{ + int ret, size; + + Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); + size = pwc_decode_size(pdev, width, height); + if (size < 0) { + Debug("Could not find suitable size.\n"); + return -ERANGE; + } + Debug("decode_size = %d.\n", size); + + ret = -EINVAL; + switch(pdev->type) { + case 645: + case 646: + ret = set_video_mode_Nala(pdev, size, frames); + break; + + case 675: + case 680: + case 690: + ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); + break; + + case 720: + case 730: + case 740: + case 750: + ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); + break; + } + if (ret < 0) { + if (ret == -ENOENT) + Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); + else { + Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); + } + return ret; + } + pdev->view.x = width; + pdev->view.y = height; + pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; + pwc_set_image_buffer_size(pdev); + Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); + return 0; +} + + +void pwc_set_image_buffer_size(struct pwc_device *pdev) +{ + int i, factor = 0, filler = 0; + + /* for PALETTE_YUV420P */ + switch(pdev->vpalette) + { + case VIDEO_PALETTE_YUV420P: + factor = 6; + filler = 128; + break; + case VIDEO_PALETTE_RAW: + factor = 6; /* can be uncompressed YUV420P */ + filler = 0; + break; + } + + /* Set sizes in bytes */ + pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; + pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; + + /* Align offset, or you'll get some very weird results in + YUV420 mode... x must be multiple of 4 (to get the Y's in + place), and y even (or you'll mixup U & V). This is less of a + problem for YUV420P. + */ + pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; + pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; + + /* Fill buffers with gray or black */ + for (i = 0; i < MAX_IMAGES; i++) { + if (pdev->image_ptr[i] != NULL) + memset(pdev->image_ptr[i], filler, pdev->view.size); + } +} + + + +/* BRIGHTNESS */ + +int pwc_get_brightness(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); + if (ret < 0) + return ret; + return buf << 9; +} + +int pwc_set_brightness(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 9) & 0x7f; + return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); +} + +/* CONTRAST */ + +int pwc_get_contrast(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); + if (ret < 0) + return ret; + return buf << 10; +} + +int pwc_set_contrast(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 10) & 0x3f; + return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); +} + +/* GAMMA */ + +int pwc_get_gamma(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); + if (ret < 0) + return ret; + return buf << 11; +} + +int pwc_set_gamma(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 11) & 0x1f; + return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); +} + + +/* SATURATION */ + +int pwc_get_saturation(struct pwc_device *pdev) +{ + char buf; + int ret; + + if (pdev->type < 675) + return -1; + ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); + if (ret < 0) + return ret; + return 32768 + buf * 327; +} + +int pwc_set_saturation(struct pwc_device *pdev, int value) +{ + char buf; + + if (pdev->type < 675) + return -EINVAL; + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + /* saturation ranges from -100 to +100 */ + buf = (value - 32768) / 327; + return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); +} + +/* AGC */ + +static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) +{ + char buf; + int ret; + + if (mode) + buf = 0x0; /* auto */ + else + buf = 0xff; /* fixed */ + + ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); + + if (!mode && ret >= 0) { + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 10) & 0x3F; + ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); + } + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_agc(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); + if (ret < 0) + return ret; + + if (buf != 0) { /* fixed */ + ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); + if (ret < 0) + return ret; + if (buf > 0x3F) + buf = 0x3F; + *value = (buf << 10); + } + else { /* auto */ + ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); + if (ret < 0) + return ret; + /* Gah... this value ranges from 0x00 ... 0x9F */ + if (buf > 0x9F) + buf = 0x9F; + *value = -(48 + buf * 409); + } + + return 0; +} + +static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) +{ + char buf[2]; + int speed, ret; + + + if (mode) + buf[0] = 0x0; /* auto */ + else + buf[0] = 0xff; /* fixed */ + + ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); + + if (!mode && ret >= 0) { + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + switch(pdev->type) { + case 675: + case 680: + case 690: + /* speed ranges from 0x0 to 0x290 (656) */ + speed = (value / 100); + buf[1] = speed >> 8; + buf[0] = speed & 0xff; + break; + case 720: + case 730: + case 740: + case 750: + /* speed seems to range from 0x0 to 0xff */ + buf[1] = 0; + buf[0] = value >> 8; + break; + } + + ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); + } + return ret; +} + + +/* POWER */ + +int pwc_camera_power(struct pwc_device *pdev, int power) +{ + char buf; + + if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) + return 0; /* Not supported by Nala or Timon < release 6 */ + + if (power) + buf = 0x00; /* active */ + else + buf = 0xFF; /* power save */ + return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); +} + + + +/* private calls */ + +static inline int pwc_restore_user(struct pwc_device *pdev) +{ + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); +} + +static inline int pwc_save_user(struct pwc_device *pdev) +{ + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); +} + +static inline int pwc_restore_factory(struct pwc_device *pdev) +{ + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); +} + + /* ************************************************* */ + /* Patch by Alvarado: (not in the original version */ + + /* + * the camera recognizes modes from 0 to 4: + * + * 00: indoor (incandescant lighting) + * 01: outdoor (sunlight) + * 02: fluorescent lighting + * 03: manual + * 04: auto + */ +static inline int pwc_set_awb(struct pwc_device *pdev, int mode) +{ + char buf; + int ret; + + if (mode < 0) + mode = 0; + + if (mode > 4) + mode = 4; + + buf = mode & 0x07; /* just the lowest three bits */ + + ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); + + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_awb(struct pwc_device *pdev) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); + + if (ret < 0) + return ret; + return buf; +} + +static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) +{ + unsigned char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + /* only the msb is considered */ + buf = value >> 8; + return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); +} + +static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + + +static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value) +{ + unsigned char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + /* only the msb is considered */ + buf = value >> 8; + return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); +} + +static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + + +/* The following two functions are different, since they only read the + internal red/blue gains, which may be different from the manual + gains set or read above. + */ +static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + +static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + + +static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) +{ + unsigned char buf; + + /* useful range is 0x01..0x20 */ + buf = speed / 0x7f0; + return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); +} + +static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf * 0x7f0; + return 0; +} + + +static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) +{ + unsigned char buf; + + /* useful range is 0x01..0x3F */ + buf = (delay >> 10); + return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); +} + +static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 10; + return 0; +} + + +int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) +{ + unsigned char buf[2]; + + if (pdev->type < 730) + return 0; + on_value /= 100; + off_value /= 100; + if (on_value < 0) + on_value = 0; + if (on_value > 0xff) + on_value = 0xff; + if (off_value < 0) + off_value = 0; + if (off_value > 0xff) + off_value = 0xff; + + buf[0] = on_value; + buf[1] = off_value; + + return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); +} + +int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) +{ + unsigned char buf[2]; + int ret; + + if (pdev->type < 730) { + *on_value = -1; + *off_value = -1; + return 0; + } + + ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); + if (ret < 0) + return ret; + *on_value = buf[0] * 100; + *off_value = buf[1] * 100; + return 0; +} + +static inline int pwc_set_contour(struct pwc_device *pdev, int contour) +{ + unsigned char buf; + int ret; + + if (contour < 0) + buf = 0xff; /* auto contour on */ + else + buf = 0x0; /* auto contour off */ + ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + + if (contour < 0) + return 0; + if (contour > 0xffff) + contour = 0xffff; + + buf = (contour >> 10); /* contour preset is [0..3f] */ + ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + + if (buf == 0) { + /* auto mode off, query current preset value */ + ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + *contour = buf << 10; + } + else + *contour = -1; + return 0; +} + + +static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) +{ + unsigned char buf; + + if (backlight) + buf = 0xff; + else + buf = 0x0; + return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); +} + +static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); + if (ret < 0) + return ret; + *backlight = buf; + return 0; +} + + +static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) +{ + unsigned char buf; + + if (flicker) + buf = 0xff; + else + buf = 0x0; + return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); +} + +static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); + if (ret < 0) + return ret; + *flicker = buf; + return 0; +} + + +static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) +{ + unsigned char buf; + + if (noise < 0) + noise = 0; + if (noise > 3) + noise = 3; + buf = noise; + return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); +} + +static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); + if (ret < 0) + return ret; + *noise = buf; + return 0; +} + +int pwc_mpt_reset(struct pwc_device *pdev, int flags) +{ + unsigned char buf; + + buf = flags & 0x03; // only lower two bits are currently used + return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); +} + +static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) +{ + unsigned char buf[4]; + + /* set new relative angle; angles are expressed in degrees * 100, + but cam as .5 degree resolution, hence devide by 200. Also + the angle must be multiplied by 64 before it's send to + the cam (??) + */ + pan = 64 * pan / 100; + tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ + buf[0] = pan & 0xFF; + buf[1] = (pan >> 8) & 0xFF; + buf[2] = tilt & 0xFF; + buf[3] = (tilt >> 8) & 0xFF; + return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); +} + +static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) +{ + int ret; + unsigned char buf[5]; + + ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); + if (ret < 0) + return ret; + status->status = buf[0] & 0x7; // 3 bits are used for reporting + status->time_pan = (buf[1] << 8) + buf[2]; + status->time_tilt = (buf[3] << 8) + buf[4]; + return 0; +} + + +int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) +{ + unsigned char buf; + int ret = -1, request; + + if (pdev->type < 675) + request = SENSOR_TYPE_FORMATTER1; + else if (pdev->type < 730) + return -1; /* The Vesta series doesn't have this call */ + else + request = SENSOR_TYPE_FORMATTER2; + + ret = RecvControlMsg(GET_STATUS_CTL, request, 1); + if (ret < 0) + return ret; + if (pdev->type < 675) + *sensor = buf | 0x100; + else + *sensor = buf; + return 0; +} + + + /* End of Add-Ons */ + /* ************************************************* */ + +/* Linux 2.5.something and 2.6 pass direct pointers to arguments of + ioctl() calls. With 2.4, you have to do tedious copy_from_user() + and copy_to_user() calls. With these macros we circumvent this, + and let me maintain only one source file. The functionality is + exactly the same otherwise. + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + +/* define local variable for arg */ +#define ARG_DEF(ARG_type, ARG_name)\ + ARG_type *ARG_name = arg; +/* copy arg to local variable */ +#define ARG_IN(ARG_name) /* nothing */ +/* argument itself (referenced) */ +#define ARGR(ARG_name) (*ARG_name) +/* argument address */ +#define ARGA(ARG_name) ARG_name +/* copy local variable to arg */ +#define ARG_OUT(ARG_name) /* nothing */ + +#else + +#define ARG_DEF(ARG_type, ARG_name)\ + ARG_type ARG_name; +#define ARG_IN(ARG_name)\ + if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\ + ret = -EFAULT;\ + break;\ + } +#define ARGR(ARG_name) ARG_name +#define ARGA(ARG_name) &ARG_name +#define ARG_OUT(ARG_name)\ + if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\ + ret = -EFAULT;\ + break;\ + } + +#endif + +int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) +{ + int ret = 0; + + switch(cmd) { + case VIDIOCPWCRUSER: + { + if (pwc_restore_user(pdev)) + ret = -EINVAL; + break; + } + + case VIDIOCPWCSUSER: + { + if (pwc_save_user(pdev)) + ret = -EINVAL; + break; + } + + case VIDIOCPWCFACTORY: + { + if (pwc_restore_factory(pdev)) + ret = -EINVAL; + break; + } + + case VIDIOCPWCSCQUAL: + { + ARG_DEF(int, qual) + + ARG_IN(qual) + if (ARGR(qual) < 0 || ARGR(qual) > 3) + ret = -EINVAL; + else + ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); + if (ret >= 0) + pdev->vcompression = ARGR(qual); + break; + } + + case VIDIOCPWCGCQUAL: + { + ARG_DEF(int, qual) + + ARGR(qual) = pdev->vcompression; + ARG_OUT(qual) + break; + } + + case VIDIOCPWCPROBE: + { + ARG_DEF(struct pwc_probe, probe) + + strcpy(ARGR(probe).name, pdev->vdev->name); + ARGR(probe).type = pdev->type; + ARG_OUT(probe) + break; + } + + case VIDIOCPWCGSERIAL: + { + ARG_DEF(struct pwc_serial, serial) + + strcpy(ARGR(serial).serial, pdev->serial); + ARG_OUT(serial) + break; + } + + case VIDIOCPWCSAGC: + { + ARG_DEF(int, agc) + + ARG_IN(agc) + if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) + ret = -EINVAL; + break; + } + + case VIDIOCPWCGAGC: + { + ARG_DEF(int, agc) + + if (pwc_get_agc(pdev, ARGA(agc))) + ret = -EINVAL; + ARG_OUT(agc) + break; + } + + case VIDIOCPWCSSHUTTER: + { + ARG_DEF(int, shutter_speed) + + ARG_IN(shutter_speed) + ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); + break; + } + + case VIDIOCPWCSAWB: + { + ARG_DEF(struct pwc_whitebalance, wb) + + ARG_IN(wb) + ret = pwc_set_awb(pdev, ARGR(wb).mode); + if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { + pwc_set_red_gain(pdev, ARGR(wb).manual_red); + pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); + } + break; + } + + case VIDIOCPWCGAWB: + { + ARG_DEF(struct pwc_whitebalance, wb) + + memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); + ARGR(wb).mode = pwc_get_awb(pdev); + if (ARGR(wb).mode < 0) + ret = -EINVAL; + else { + if (ARGR(wb).mode == PWC_WB_MANUAL) { + ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); + if (ret < 0) + break; + ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); + if (ret < 0) + break; + } + if (ARGR(wb).mode == PWC_WB_AUTO) { + ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); + if (ret < 0) + break; + ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); + if (ret < 0) + break; + } + } + ARG_OUT(wb) + break; + } + + case VIDIOCPWCSAWBSPEED: + { + ARG_DEF(struct pwc_wb_speed, wbs) + + if (ARGR(wbs).control_speed > 0) { + ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); + } + if (ARGR(wbs).control_delay > 0) { + ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); + } + break; + } + + case VIDIOCPWCGAWBSPEED: + { + ARG_DEF(struct pwc_wb_speed, wbs) + + ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); + if (ret < 0) + break; + ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); + if (ret < 0) + break; + ARG_OUT(wbs) + break; + } + + case VIDIOCPWCSLED: + { + ARG_DEF(struct pwc_leds, leds) + + ARG_IN(leds) + ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); + break; + } + + + case VIDIOCPWCGLED: + { + ARG_DEF(struct pwc_leds, leds) + + ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); + ARG_OUT(leds) + break; + } + + case VIDIOCPWCSCONTOUR: + { + ARG_DEF(int, contour) + + ARG_IN(contour) + ret = pwc_set_contour(pdev, ARGR(contour)); + break; + } + + case VIDIOCPWCGCONTOUR: + { + ARG_DEF(int, contour) + + ret = pwc_get_contour(pdev, ARGA(contour)); + ARG_OUT(contour) + break; + } + + case VIDIOCPWCSBACKLIGHT: + { + ARG_DEF(int, backlight) + + ARG_IN(backlight) + ret = pwc_set_backlight(pdev, ARGR(backlight)); + break; + } + + case VIDIOCPWCGBACKLIGHT: + { + ARG_DEF(int, backlight) + + ret = pwc_get_backlight(pdev, ARGA(backlight)); + ARG_OUT(backlight) + break; + } + + case VIDIOCPWCSFLICKER: + { + ARG_DEF(int, flicker) + + ARG_IN(flicker) + ret = pwc_set_flicker(pdev, ARGR(flicker)); + break; + } + + case VIDIOCPWCGFLICKER: + { + ARG_DEF(int, flicker) + + ret = pwc_get_flicker(pdev, ARGA(flicker)); + ARG_OUT(flicker) + break; + } + + case VIDIOCPWCSDYNNOISE: + { + ARG_DEF(int, dynnoise) + + ARG_IN(dynnoise) + ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); + break; + } + + case VIDIOCPWCGDYNNOISE: + { + ARG_DEF(int, dynnoise) + + ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); + ARG_OUT(dynnoise); + break; + } + + case VIDIOCPWCGREALSIZE: + { + ARG_DEF(struct pwc_imagesize, size) + + ARGR(size).width = pdev->image.x; + ARGR(size).height = pdev->image.y; + ARG_OUT(size) + break; + } + + case VIDIOCPWCMPTRESET: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(int, flags) + + ARG_IN(flags) + ret = pwc_mpt_reset(pdev, ARGR(flags)); + if (ret >= 0) + { + pdev->pan_angle = 0; + pdev->tilt_angle = 0; + } + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTGRANGE: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_range, range) + + ARGR(range) = pdev->angle_range; + ARG_OUT(range) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTSANGLE: + { + int new_pan, new_tilt; + + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_angles, angles) + + ARG_IN(angles) + /* The camera can only set relative angles, so + do some calculations when getting an absolute angle . + */ + if (ARGR(angles).absolute) + { + new_pan = ARGR(angles).pan; + new_tilt = ARGR(angles).tilt; + } + else + { + new_pan = pdev->pan_angle + ARGR(angles).pan; + new_tilt = pdev->tilt_angle + ARGR(angles).tilt; + } + /* check absolute ranges */ + if (new_pan < pdev->angle_range.pan_min || + new_pan > pdev->angle_range.pan_max || + new_tilt < pdev->angle_range.tilt_min || + new_tilt > pdev->angle_range.tilt_max) + { + ret = -ERANGE; + } + else + { + /* go to relative range, check again */ + new_pan -= pdev->pan_angle; + new_tilt -= pdev->tilt_angle; + /* angles are specified in degrees * 100, thus the limit = 36000 */ + if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000) + ret = -ERANGE; + } + if (ret == 0) /* no errors so far */ + { + ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); + if (ret >= 0) + { + pdev->pan_angle += new_pan; + pdev->tilt_angle += new_tilt; + } + if (ret == -EPIPE) /* stall -> out of range */ + ret = -ERANGE; + } + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTGANGLE: + { + + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_angles, angles) + + ARGR(angles).absolute = 1; + ARGR(angles).pan = pdev->pan_angle; + ARGR(angles).tilt = pdev->tilt_angle; + ARG_OUT(angles) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTSTATUS: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_status, status) + + ret = pwc_mpt_get_status(pdev, ARGA(status)); + ARG_OUT(status) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCGVIDCMD: + { + ARG_DEF(struct pwc_video_command, cmd); + + ARGR(cmd).type = pdev->type; + ARGR(cmd).release = pdev->release; + ARGR(cmd).command_len = pdev->cmd_len; + memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); + ARGR(cmd).bandlength = pdev->vbandlength; + ARGR(cmd).frame_size = pdev->frame_size; + ARG_OUT(cmd) + break; + } + /* + case VIDIOCPWCGVIDTABLE: + { + ARG_DEF(struct pwc_table_init_buffer, table); + ARGR(table).len = pdev->cmd_len; + memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); + ARG_OUT(table) + break; + } + */ + + default: + ret = -ENOIOCTLCMD; + break; + } + + if (ret > 0) + return 0; + return ret; +} + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec1.c linux-2.6.9/drivers/usb/media/pwc/pwc-dec1.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec1.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-dec1.c 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,42 @@ +/* Linux driver for Philips webcam + Decompression for chipset version 1 + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 "pwc-dec1.h" + + +void pwc_dec1_init(int type, int release, void *buffer, void *table) +{ + +} + +void pwc_dec1_exit(void) +{ + + + +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec1.h linux-2.6.9/drivers/usb/media/pwc/pwc-dec1.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec1.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-dec1.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,36 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + + + +#ifndef PWC_DEC1_H +#define PWC_DEC1_H + +void pwc_dec1_init(int type, int release, void *buffer, void *private_data); +void pwc_dec1_exit(void); + +#endif + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec23.c linux-2.6.9/drivers/usb/media/pwc/pwc-dec23.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec23.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-dec23.c 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,623 @@ +/* Linux driver for Philips webcam + Decompression for chipset version 2 et 3 + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 "pwc-timon.h" +#include "pwc-kiara.h" +#include "pwc-dec23.h" +#include "pwc-ioctl.h" + +#include + +/**** + * + * + * + */ + + +static void fill_table_a000(unsigned int *p) +{ + static unsigned int initial_values[12] = { + 0xFFAD9B00, 0xFFDDEE00, 0x00221200, 0x00526500, + 0xFFC21E00, 0x003DE200, 0xFF924B80, 0xFFD2A300, + 0x002D5D00, 0x006DB480, 0xFFED3E00, 0x0012C200 + }; + static unsigned int values_derivated[12] = { + 0x0000A4CA, 0x00004424, 0xFFFFBBDC, 0xFFFF5B36, + 0x00007BC4, 0xFFFF843C, 0x0000DB69, 0x00005ABA, + 0xFFFFA546, 0xFFFF2497, 0x00002584, 0xFFFFDA7C + }; + unsigned int temp_values[12]; + int i,j; + + memcpy(temp_values,initial_values,sizeof(initial_values)); + for (i=0;i<256;i++) + { + for (j=0;j<12;j++) + { + *p++ = temp_values[j]; + temp_values[j] += values_derivated[j]; + } + } +} + +static void fill_table_d000(unsigned char *p) +{ + int bit,byte; + + for (bit=0; bit<8; bit++) + { + unsigned char bitpower = 1<=1 && k<3) + bit=(table[0]>>15)&7; + else if (k>=3 && k<6) + bit=(table[0]>>12)&7; + else if (k>=6 && k<10) + bit=(table[0]>>9)&7; + else if (k>=10 && k<13) + bit=(table[0]>>6)&7; + else if (k>=13 && k<15) + bit=(table[0]>>3)&7; + else + bit=(table[0])&7; + if (k == 0) + *(unsigned char *)p8++ = 8; + else + *(unsigned char *)p8++ = j - bit; + *(unsigned char *)p8++ = bit; + + pw = 1<xx + pdev->yy) + * + */ +void fill_table_dc00_d800(unsigned int precision, unsigned int *pdc00, unsigned int *pd800) +{ + int i; + unsigned int offset1, offset2; + + for(i=0,offset1=0x4000, offset2=0; i<256 ; i++,offset1+=0x7BC4, offset2+=0x7BC4) + { + unsigned int msb = offset1 >> 15; + + if ( msb > 255) + { + if (msb) + msb=0; + else + msb=255; + } + + *pdc00++ = msb << precision; + *pd800++ = offset2; + } + +} + +/* + * struct { + * unsigned char op; // operation to execute + * unsigned char bits; // bits use to perform operation + * unsigned char offset1; // offset to add to access in the table_0004 % 16 + * unsigned char offset2; // offset to add to access in the table_0004 + * } + * + */ +static unsigned int table_ops[] = { +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x30, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x10, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x70, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x50, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00 +}; + +/* + * TODO: multiply by 4 all values + * + */ +static unsigned int MulIdx[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, + 6, 7, 8, 9, 7,10,11, 8, 8,11,10, 7, 9, 8, 7, 6, + 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, + 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, + 0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3, + 0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3, + 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2, + 7,10,11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8,11,10, 7, + 4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4, + 7, 9, 6, 8,10, 8, 7,11,11, 7, 8,10, 8, 6, 9, 7, + 1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2, + 1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2, +10, 8, 7,11, 8, 6, 9, 7, 7, 9, 6, 8,11, 7, 8,10 +}; + + + +void pwc_dec23_init(int type, int release, unsigned char *mode, void *data) +{ + int flags; + struct pwc_dec23_private *pdev = data; + release = release; + + switch (type) + { + case 720: + case 730: + case 740: + case 750: + flags = mode[2]&0x18; /* our: flags = 8, mode[2]==e8 */ + if (flags==8) + pdev->zz = 7; + else if (flags==0x10) + pdev->zz = 8; + else + pdev->zz = 6; + flags = mode[2]>>5; /* our: 7 */ + + fill_table_color(flags, (unsigned int *)KiaraRomTable, pdev->table_0004, pdev->table_8004); + break; + + + case 675: + case 680: + case 690: + flags = mode[2]&6; + if (flags==2) + pdev->zz = 7; + else if (flags==4) + pdev->zz = 8; + else + pdev->zz = 6; + flags = mode[2]>>3; + + fill_table_color(flags, (unsigned int *)TimonRomTable, pdev->table_0004, pdev->table_8004); + break; + + default: + /* Not supported */ + return; + } + + /* * * * ** */ + pdev->xx = 8 - pdev->zz; + pdev->yy = 15 - pdev->xx; + pdev->zzmask = 0xFF>>pdev->xx; + //pdev->zzmask = (1U<zz)-1; + + + fill_table_dc00_d800(pdev->xx + pdev->yy, pdev->table_dc00, pdev->table_d800); + fill_table_a000(pdev->table_a004); + fill_table_d000(pdev->table_d004); +} + + +/* + * To manage the stream, we keep in a 32 bits variables, + * the next bits in the stream. fill_reservoir() add to + * the reservoir at least wanted nbits. + * + * + */ +#define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ + while (nbits_in_reservoir>= nbits_wanted; \ + nbits_in_reservoir -= nbits_wanted; \ +} while(0); + + + +static void DecompressBand23(const struct pwc_dec23_private *pdev, + const unsigned char *rawyuv, + unsigned char *planar_y, + unsigned char *planar_u, + unsigned char *planar_v, + unsigned int image_x, /* aka number of pixels wanted ??? */ + unsigned int pixels_per_line, /* aka number of pixels per line */ + int flags) +{ + + + unsigned int reservoir, nbits_in_reservoir; + int first_4_bits; + unsigned int bytes_per_channel; + int line_size; /* size of the line (4Y+U+V) */ + int passes; + const unsigned char *ptable0004, *ptable8004; + + int even_line; + unsigned int temp_colors[16]; + int nblocks; + + const unsigned char *stream; + unsigned char *dest_y, *dest_u=NULL, *dest_v=NULL; + unsigned int offset_to_plane_u, offset_to_plane_v; + + int i; + + + reservoir = 0; + nbits_in_reservoir = 0; + stream = rawyuv+1; /* The first byte of the stream is skipped */ + even_line = 1; + + get_nbits(reservoir,nbits_in_reservoir,stream,4,first_4_bits); + + line_size = pixels_per_line*3; + + for (passes=0;passes<2;passes++) + { + if (passes==0) + { + bytes_per_channel = pixels_per_line; + dest_y = planar_y; + nblocks = image_x/4; + } + else + { + /* Format planar: All Y, then all U, then all V */ + bytes_per_channel = pixels_per_line/2; + dest_u = planar_u; + dest_v = planar_v; + dest_y = dest_u; + nblocks = image_x/8; + } + + offset_to_plane_u = bytes_per_channel*2; + offset_to_plane_v = bytes_per_channel*3; + /* + printf("bytes_per_channel = %d\n",bytes_per_channel); + printf("offset_to_plane_u = %d\n",offset_to_plane_u); + printf("offset_to_plane_v = %d\n",offset_to_plane_v); + */ + + while (nblocks-->0) + { + unsigned int gray_index; + + fill_nbits(reservoir,nbits_in_reservoir,stream,16); + gray_index = reservoir & pdev->zzmask; + reservoir >>= pdev->zz; + nbits_in_reservoir -= pdev->zz; + + fill_nbits(reservoir,nbits_in_reservoir,stream,2); + + if ( (reservoir & 3) == 0) + { + reservoir>>=2; + nbits_in_reservoir-=2; + for (i=0;i<16;i++) + temp_colors[i] = pdev->table_dc00[gray_index]; + + } + else + { + unsigned int channel_v, offset1; + + /* swap bit 0 and 2 of offset_OR */ + channel_v = ((reservoir & 1) << 2) | (reservoir & 2) | ((reservoir & 4)>>2); + reservoir>>=3; + nbits_in_reservoir-=3; + + for (i=0;i<16;i++) + temp_colors[i] = pdev->table_d800[gray_index]; + + ptable0004 = pdev->table_0004 + (passes*16384) + (first_4_bits*1024) + (channel_v*128); + ptable8004 = pdev->table_8004 + (passes*4096) + (first_4_bits*256) + (channel_v*32); + + offset1 = 0; + while(1) + { + unsigned int index_in_table_ops, op, rows=0; + fill_nbits(reservoir,nbits_in_reservoir,stream,16); + + /* mode is 0,1 or 2 */ + index_in_table_ops = (reservoir&0x3F); + op = table_ops[ index_in_table_ops*4 ]; + if (op == 2) + { + reservoir >>= 2; + nbits_in_reservoir -= 2; + break; /* exit the while(1) */ + } + if (op == 0) + { + unsigned int shift; + + offset1 = (offset1 + table_ops[index_in_table_ops*4+2]) & 0x0F; + shift = table_ops[ index_in_table_ops*4+1 ]; + reservoir >>= shift; + nbits_in_reservoir -= shift; + rows = ptable0004[ offset1 + table_ops[index_in_table_ops*4+3] ]; + } + if (op == 1) + { + /* 10bits [ xxxx xxxx yyyy 000 ] + * yyy => offset in the table8004 + * xxx => offset in the tabled004 + */ + unsigned int mask, shift; + unsigned int col1, row1, total_bits; + + offset1 = (offset1 + ((reservoir>>3)&0x0F)+1) & 0x0F; + + col1 = (reservoir>>7) & 0xFF; + row1 = ptable8004 [ offset1*2 ]; + + /* Bit mask table */ + mask = pdev->table_d004[ (row1<<8) + col1 ]; + shift = ptable8004 [ offset1*2 + 1]; + rows = ((mask << shift) + 0x80) & 0xFF; + + total_bits = row1 + 8; + reservoir >>= total_bits; + nbits_in_reservoir -= total_bits; + } + { + const unsigned int *table_a004 = pdev->table_a004 + rows*12; + unsigned int *poffset = MulIdx + offset1*16; /* 64/4 (int) */ + for (i=0;i<16;i++) + { + temp_colors[i] += table_a004[ *poffset ]; + poffset++; + } + } + } + } +#define USE_SIGNED_INT_FOR_COLOR +#ifdef USE_SIGNED_INT_FOR_COLOR +# define CLAMP(x) ((x)>255?255:((x)<0?0:x)) +#else +# define CLAMP(x) ((x)>255?255:x) +#endif + + if (passes == 0) + { +#ifdef USE_SIGNED_INT_FOR_COLOR + const int *c = temp_colors; +#else + const unsigned int *c = temp_colors; +#endif + unsigned char *d; + + d = dest_y; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + bytes_per_channel; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + offset_to_plane_u; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + offset_to_plane_v; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + dest_y += 4; + } + else if (passes == 1) + { +#ifdef USE_SIGNED_INT_FOR_COLOR + int *c1 = temp_colors; + int *c2 = temp_colors+4; +#else + unsigned int *c1 = temp_colors; + unsigned int *c2 = temp_colors+4; +#endif + unsigned char *d; + + d = dest_y; + for (i=0;i<4;i++,c1++,c2++) + { + *d++ = CLAMP((*c1) >> pdev->yy); + *d++ = CLAMP((*c2) >> pdev->yy); + } + c1 = temp_colors+12; + //c2 = temp_colors+8; + d = dest_y + bytes_per_channel; + for (i=0;i<4;i++,c1++,c2++) + { + *d++ = CLAMP((*c1) >> pdev->yy); + *d++ = CLAMP((*c2) >> pdev->yy); + } + + if (even_line) /* Each line, swap u/v */ + { + even_line=0; + dest_y = dest_v; + dest_u += 8; + } + else + { + even_line=1; + dest_y = dest_u; + dest_v += 8; + } + } + + } /* end of while (nblocks-->0) */ + + } /* end of for (passes=0;passes<2;passes++) */ + +} + + +/** + * + * image: size of the image wanted + * view : size of the image returned by the camera + * offset: (x,y) to displayer image in the view + * + * src: raw data + * dst: image output + * flags: PWCX_FLAG_PLANAR + * pdev: private buffer + * bandlength: + * + */ +void pwc_dec23_decompress(const struct pwc_coord *image, + const struct pwc_coord *view, + const struct pwc_coord *offset, + const void *src, + void *dst, + int flags, + const void *data, + int bandlength) +{ + const struct pwc_dec23_private *pdev = data; + unsigned char *pout, *pout_planar_y=NULL, *pout_planar_u=NULL, *pout_planar_v=NULL; + int i,n,stride,pixel_size; + + + if (flags & PWCX_FLAG_BAYER) + { + pout = dst + (view->x * offset->y) + offset->x; + pixel_size = view->x * 4; + } + else + { + n = view->x * view->y; + + /* offset in Y plane */ + stride = view->x * offset->y; + pout_planar_y = dst + stride + offset->x; + + /* offsets in U/V planes */ + stride = (view->x * offset->y)/4 + offset->x/2; + pout_planar_u = dst + n + + stride; + pout_planar_v = dst + n + n/4 + stride; + + pixel_size = view->x * 4; + } + + + for (i=0;iy;i+=4) + { + if (flags & PWCX_FLAG_BAYER) + { + //TODO: + //DecompressBandBayer(pdev,src,pout,image.x,view->x,flags); + src += bandlength; + pout += pixel_size; + } + else + { + DecompressBand23(pdev,src,pout_planar_y,pout_planar_u,pout_planar_v,image->x,view->x,flags); + src += bandlength; + pout_planar_y += pixel_size; + pout_planar_u += view->x; + pout_planar_v += view->x; + } + } +} + +void pwc_dec23_exit(void) +{ + /* Do nothing */ + +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec23.h linux-2.6.9/drivers/usb/media/pwc/pwc-dec23.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-dec23.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-dec23.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,58 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + +#ifndef PWC_DEC23_H +#define PWC_DEC23_H + +struct pwc_dec23_private +{ + unsigned char xx,yy,zz,zzmask; + + unsigned char table_0004[2*0x4000]; + unsigned char table_8004[2*0x1000]; + unsigned int table_a004[256*12]; + + unsigned char table_d004[8*256]; + unsigned int table_d800[256]; + unsigned int table_dc00[256]; +}; + + +void pwc_dec23_init(int type, int release, unsigned char *buffer, void *private_data); +void pwc_dec23_exit(void); +void pwc_dec23_decompress(const struct pwc_coord *image, + const struct pwc_coord *view, + const struct pwc_coord *offset, + const void *src, + void *dst, + int flags, + const void *data, + int bandlength); + + + +#endif + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc.h linux-2.6.9/drivers/usb/media/pwc/pwc.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,278 @@ +/* (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + +#ifndef PWC_H +#define PWC_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwc-uncompress.h" +#include "pwc-ioctl.h" + +/* Defines and structures for the Philips webcam */ +/* Used for checking memory corruption/pointer validation */ +#define PWC_MAGIC 0x89DC10ABUL +#undef PWC_MAGIC + +/* Turn some debugging options on/off */ +#define PWC_DEBUG 0 + +/* Trace certain actions in the driver */ +#define TRACE_MODULE 0x0001 +#define TRACE_PROBE 0x0002 +#define TRACE_OPEN 0x0004 +#define TRACE_READ 0x0008 +#define TRACE_MEMORY 0x0010 +#define TRACE_FLOW 0x0020 +#define TRACE_SIZE 0x0040 +#define TRACE_PWCX 0x0080 +#define TRACE_SEQUENCE 0x1000 + +#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) +#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) +#define Info(A...) printk(KERN_INFO PWC_NAME " " A) +#define Err(A...) printk(KERN_ERR PWC_NAME " " A) + + +/* Defines for ToUCam cameras */ +#define TOUCAM_HEADER_SIZE 8 +#define TOUCAM_TRAILER_SIZE 4 + +#define FEATURE_MOTOR_PANTILT 0x0001 + +/* Version block */ +#define PWC_MAJOR 9 +#define PWC_MINOR 0 +#define PWC_VERSION "9.0.2-unofficial" +#define PWC_NAME "pwc" + +/* Turn certain features on/off */ +#define PWC_INT_PIPE 0 + +/* Ignore errors in the first N frames, to allow for startup delays */ +#define FRAME_LOWMARK 5 + +/* Size and number of buffers for the ISO pipe. */ +#define MAX_ISO_BUFS 2 +#define ISO_FRAMES_PER_DESC 10 +#define ISO_MAX_FRAME_SIZE 960 +#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) + +/* Frame buffers: contains compressed or uncompressed video data. */ +#define MAX_FRAMES 5 +/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ +#define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) + +/* Absolute maximum number of buffers available for mmap() */ +#define MAX_IMAGES 10 + +/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ +struct pwc_iso_buf +{ + void *data; + int length; + int read; + struct urb *urb; +}; + +/* intermediate buffers with raw data from the USB cam */ +struct pwc_frame_buf +{ + void *data; + volatile int filled; /* number of bytes filled */ + struct pwc_frame_buf *next; /* list */ +#if PWC_DEBUG + int sequence; /* Sequence number */ +#endif +}; + +struct pwc_device +{ + struct video_device *vdev; +#ifdef PWC_MAGIC + int magic; +#endif + /* Pointer to our usb_device */ + struct usb_device *udev; + + int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ + int release; /* release number */ + int features; /* feature bits */ + char serial[30]; /* serial number (string) */ + int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ + int usb_init; /* set when the cam has been initialized over USB */ + + /*** Video data ***/ + int vopen; /* flag */ + int vendpoint; /* video isoc endpoint */ + int vcinterface; /* video control interface */ + int valternate; /* alternate interface needed */ + int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ + int vpalette; /* palette: 420P, RAW or RGBBAYER */ + int vframe_count; /* received frames */ + int vframes_dumped; /* counter for dumped frames */ + int vframes_error; /* frames received in error */ + int vmax_packet_size; /* USB maxpacket size */ + int vlast_packet_size; /* for frame synchronisation */ + int visoc_errors; /* number of contiguous ISOC errors */ + int vcompression; /* desired compression factor */ + int vbandlength; /* compressed band length; 0 is uncompressed */ + char vsnapshot; /* snapshot mode */ + char vsync; /* used by isoc handler */ + char vmirror; /* for ToUCaM series */ + + int cmd_len; + unsigned char cmd_buf[13]; + + /* The image acquisition requires 3 to 4 steps: + 1. data is gathered in short packets from the USB controller + 2. data is synchronized and packed into a frame buffer + 3a. in case data is compressed, decompress it directly into image buffer + 3b. in case data is uncompressed, copy into image buffer with viewport + 4. data is transferred to the user process + + Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... + We have in effect a back-to-back-double-buffer system. + */ + /* 1: isoc */ + struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; + char iso_init; + + /* 2: frame */ + struct pwc_frame_buf *fbuf; /* all frames */ + struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ + struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ + struct pwc_frame_buf *fill_frame; /* frame currently being filled */ + struct pwc_frame_buf *read_frame; /* frame currently read by user process */ + int frame_header_size, frame_trailer_size; + int frame_size; + int frame_total_size; /* including header & trailer */ + int drop_frames; +#if PWC_DEBUG + int sequence; /* Debugging aid */ +#endif + + /* 3: decompression */ + struct pwc_decompressor *decompressor; /* function block with decompression routines */ + void *decompress_data; /* private data for decompression engine */ + + /* 4: image */ + /* We have an 'image' and a 'view', where 'image' is the fixed-size image + as delivered by the camera, and 'view' is the size requested by the + program. The camera image is centered in this viewport, laced with + a gray or black border. view_min <= image <= view <= view_max; + */ + int image_mask; /* bitmask of supported sizes */ + struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ + struct pwc_coord abs_max; /* maximum supported size with compression */ + struct pwc_coord image, view; /* image and viewport size */ + struct pwc_coord offset; /* offset within the viewport */ + + void *image_data; /* total buffer, which is subdivided into ... */ + void *image_ptr[MAX_IMAGES]; /* ...several images... */ + int fill_image; /* ...which are rotated. */ + int len_per_image; /* length per image */ + int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ + int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ + + struct semaphore modlock; /* to prevent races in video_open(), etc */ + spinlock_t ptrlock; /* for manipulating the buffer pointers */ + + /*** motorized pan/tilt feature */ + struct pwc_mpt_range angle_range; + int pan_angle; /* in degrees * 100 */ + int tilt_angle; /* absolute angle; 0,0 is home position */ + + /*** Misc. data ***/ + wait_queue_head_t frameq; /* When waiting for a frame to finish... */ +#if PWC_INT_PIPE + void *usb_int_handler; /* for the interrupt endpoint */ +#endif +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables */ +extern int pwc_trace; +extern int pwc_preferred_compression; + +/** functions in pwc-if.c */ +int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); + +/** Functions in pwc-misc.c */ +/* sizes in pixels */ +extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; + +int pwc_decode_size(struct pwc_device *pdev, int width, int height); +void pwc_construct(struct pwc_device *pdev); + +/** Functions in pwc-ctrl.c */ +/* Request a certain video mode. Returns < 0 if not possible */ +extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); +/* Calculate the number of bytes per image (not frame) */ +extern void pwc_set_image_buffer_size(struct pwc_device *pdev); + +/* Various controls; should be obvious. Value 0..65535, or < 0 on error */ +extern int pwc_get_brightness(struct pwc_device *pdev); +extern int pwc_set_brightness(struct pwc_device *pdev, int value); +extern int pwc_get_contrast(struct pwc_device *pdev); +extern int pwc_set_contrast(struct pwc_device *pdev, int value); +extern int pwc_get_gamma(struct pwc_device *pdev); +extern int pwc_set_gamma(struct pwc_device *pdev, int value); +extern int pwc_get_saturation(struct pwc_device *pdev); +extern int pwc_set_saturation(struct pwc_device *pdev, int value); +extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); +extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); +extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); + +/* Power down or up the camera; not supported by all models */ +extern int pwc_camera_power(struct pwc_device *pdev, int power); + +/* Private ioctl()s; see pwc-ioctl.h */ +extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); + + +/** pwc-uncompress.c */ +/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ +extern int pwc_decompress(struct pwc_device *pdev); + +#ifdef __cplusplus +} +#endif + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-if.c linux-2.6.9/drivers/usb/media/pwc/pwc-if.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-if.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-if.c 2004-10-21 13:00:05.000000000 +0100 @@ -0,0 +1,2211 @@ +/* Linux driver for Philips webcam + USB and Video4Linux interface part. + (C) 1999-2004 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 + +*/ + +/* + This code forms the interface between the USB layers and the Philips + specific stuff. Some adanved stuff of the driver falls under an + NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and + is thus not distributed in source form. The binary pwcx.o module + contains the code that falls under the NDA. + + In case you're wondering: 'pwc' stands for "Philips WebCam", but + I really didn't want to type 'philips_web_cam' every time (I'm lazy as + any Linux kernel hacker, but I don't like uncomprehensible abbreviations + without explanation). + + Oh yes, convention: to disctinguish between all the various pointers to + device-structures, I use these names for the pointer variables: + udev: struct usb_device * + vdev: struct video_device * + pdev: struct pwc_devive * +*/ + +/* Contributors: + - Alvarado: adding whitebalance code + - Alistar Moire: QuickCam 3000 Pro device/product ID + - Tony Hoyle: Creative Labs Webcam 5 device/product ID + - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged + - Jk Fang: Sotec Afina Eye ID + - Xavier Roche: QuickCam Pro 4000 ID + - Jens Knudsen: QuickCam Zoom ID + - J. Debert: QuickCam for Notebooks ID +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwc.h" +#include "pwc-ioctl.h" +#include "pwc-kiara.h" +#include "pwc-timon.h" +#include "pwc-dec23.h" +#include "pwc-dec1.h" +#include "pwc-uncompress.h" + +/* Function prototypes and driver templates */ + +/* hotplug device table support */ +static struct usb_device_id pwc_device_table [] = { + { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ + { USB_DEVICE(0x0471, 0x0303) }, + { USB_DEVICE(0x0471, 0x0304) }, + { USB_DEVICE(0x0471, 0x0307) }, + { USB_DEVICE(0x0471, 0x0308) }, + { USB_DEVICE(0x0471, 0x030C) }, + { USB_DEVICE(0x0471, 0x0310) }, + { USB_DEVICE(0x0471, 0x0311) }, + { USB_DEVICE(0x0471, 0x0312) }, + { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ + { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ + { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ + { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ + { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ + { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ + { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ + { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ + { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ + { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ + { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ + { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ + { USB_DEVICE(0x055D, 0x9001) }, + { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ + { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ + { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ + { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ + { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ + { USB_DEVICE(0x0d81, 0x1900) }, + { } +}; +MODULE_DEVICE_TABLE(usb, pwc_device_table); + +static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); +static void usb_pwc_disconnect(struct usb_interface *intf); + +static struct usb_driver pwc_driver = { + .owner = THIS_MODULE, + .name = "Philips webcam", /* name */ + .id_table = pwc_device_table, + .probe = usb_pwc_probe, /* probe() */ + .disconnect = usb_pwc_disconnect, /* disconnect() */ +}; + +#define MAX_DEV_HINTS 20 +#define MAX_ISOC_ERRORS 20 + +static int default_size = PSZ_QCIF; +static int default_fps = 10; +static int default_fbufs = 3; /* Default number of frame buffers */ +static int default_mbufs = 2; /* Default number of mmap() buffers */ + int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; +static int power_save = 0; +static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ + int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ +static struct { + int type; + char serial_number[30]; + int device_node; + struct pwc_device *pdev; +} device_hint[MAX_DEV_HINTS]; + +/***/ + +static int pwc_video_open(struct inode *inode, struct file *file); +static int pwc_video_close(struct inode *inode, struct file *file); +static ssize_t pwc_video_read(struct file *file, char *buf, + size_t count, loff_t *ppos); +static unsigned int pwc_video_poll(struct file *file, poll_table *wait); +static int pwc_video_ioctl(struct inode *inode, struct file *file, + unsigned int ioctlnr, unsigned long arg); +static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); + +static struct file_operations pwc_fops = { + .owner = THIS_MODULE, + .open = pwc_video_open, + .release = pwc_video_close, + .read = pwc_video_read, + .poll = pwc_video_poll, + .mmap = pwc_video_mmap, + .ioctl = pwc_video_ioctl, + .llseek = no_llseek, +}; +static struct video_device pwc_template = { + .owner = THIS_MODULE, + .name = "Philips Webcam", /* Filled in later */ + .type = VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_PWC, + .release = video_device_release, + .fops = &pwc_fops, + .minor = -1, +}; + +/***************************************************************************/ + +/* Okay, this is some magic that I worked out and the reasoning behind it... + + The biggest problem with any USB device is of course: "what to do + when the user unplugs the device while it is in use by an application?" + We have several options: + 1) Curse them with the 7 plagues when they do (requires divine intervention) + 2) Tell them not to (won't work: they'll do it anyway) + 3) Oops the kernel (this will have a negative effect on a user's uptime) + 4) Do something sensible. + + Of course, we go for option 4. + + It happens that this device will be linked to two times, once from + usb_device and once from the video_device in their respective 'private' + pointers. This is done when the device is probed() and all initialization + succeeded. The pwc_device struct links back to both structures. + + When a device is unplugged while in use it will be removed from the + list of known USB devices; I also de-register it as a V4L device, but + unfortunately I can't free the memory since the struct is still in use + by the file descriptor. This free-ing is then deferend until the first + opportunity. Crude, but it works. + + A small 'advantage' is that if a user unplugs the cam and plugs it back + in, it should get assigned the same video device minor, but unfortunately + it's non-trivial to re-link the cam back to the video device... (that + would surely be magic! :)) +*/ + +/***************************************************************************/ +/* Private functions */ + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the area. + */ +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); /* restore the offset */ + ret = __pa(kva); + return ret; +} + +static void * rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr; + + size=PAGE_ALIGN(size); + mem=vmalloc_32(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + 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, unsigned long size) +{ + unsigned long adr; + + if (mem) + { + adr=(unsigned long) mem; + while ((long) size > 0) + { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + + + + +static int pwc_allocate_buffers(struct pwc_device *pdev) +{ + int i; + void *kbuf; + + Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); + + if (pdev == NULL) + return -ENXIO; + +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("allocate_buffers(): magic failed.\n"); + return -ENXIO; + } +#endif + /* Allocate Isochronuous pipe buffers */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (pdev->sbuf[i].data == NULL) { + kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); + if (kbuf == NULL) { + Err("Failed to allocate iso buffer %d.\n", i); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); + pdev->sbuf[i].data = kbuf; + memset(kbuf, 0, ISO_BUFFER_SIZE); + } + } + + /* Allocate frame buffer structure */ + if (pdev->fbuf == NULL) { + kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); + if (kbuf == NULL) { + Err("Failed to allocate frame buffer structure.\n"); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); + pdev->fbuf = kbuf; + memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); + } + /* create frame buffers, and make circular ring */ + for (i = 0; i < default_fbufs; i++) { + if (pdev->fbuf[i].data == NULL) { + kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ + if (kbuf == NULL) { + Err("Failed to allocate frame buffer %d.\n", i); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); + pdev->fbuf[i].data = kbuf; + memset(kbuf, 128, PWC_FRAME_SIZE); + } + } + + /* Allocate decompressor table space */ + kbuf = NULL; + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + Trace(TRACE_MEMORY,"private_data(%d)\n",sizeof(struct pwc_dec23_private)); + kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ + break; + case 645: + case 646: + /* TODO & FIXME */ + kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); + break; + } + if (kbuf == NULL) { + Err("Failed to allocate decompress table.\n"); + return -ENOMEM; + } + pdev->decompress_data = kbuf; + + /* Allocate image buffer; double buffer for mmap() */ + kbuf = rvmalloc(default_mbufs * pdev->len_per_image); + if (kbuf == NULL) { + Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); + pdev->image_data = kbuf; + for (i = 0; i < default_mbufs; i++) + pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; + for (; i < MAX_IMAGES; i++) + pdev->image_ptr[i] = NULL; + + kbuf = NULL; + + Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); + return 0; +} + +static void pwc_free_buffers(struct pwc_device *pdev) +{ + int i; + + Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); + + if (pdev == NULL) + return; +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("free_buffers(): magic failed.\n"); + return; + } +#endif + + /* Release Iso-pipe buffers */ + for (i = 0; i < MAX_ISO_BUFS; i++) + if (pdev->sbuf[i].data != NULL) { + Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); + kfree(pdev->sbuf[i].data); + pdev->sbuf[i].data = NULL; + } + + /* The same for frame buffers */ + if (pdev->fbuf != NULL) { + for (i = 0; i < default_fbufs; i++) { + if (pdev->fbuf[i].data != NULL) { + Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); + vfree(pdev->fbuf[i].data); + pdev->fbuf[i].data = NULL; + } + } + kfree(pdev->fbuf); + pdev->fbuf = NULL; + } + + /* Intermediate decompression buffer & tables */ + if (pdev->decompress_data != NULL) { + Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); + kfree(pdev->decompress_data); + pdev->decompress_data = NULL; + } + pdev->decompressor = NULL; + + /* Release image buffers */ + if (pdev->image_data != NULL) { + Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); + rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); + } + pdev->image_data = NULL; + + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); +} + +/* The frame & image buffer mess. + + Yes, this is a mess. Well, it used to be simple, but alas... In this + module, 3 buffers schemes are used to get the data from the USB bus to + the user program. The first scheme involves the ISO buffers (called thus + since they transport ISO data from the USB controller), and not really + interesting. Suffices to say the data from this buffer is quickly + gathered in an interrupt handler (pwc_isoc_handler) and placed into the + frame buffer. + + The frame buffer is the second scheme, and is the central element here. + It collects the data from a single frame from the camera (hence, the + name). Frames are delimited by the USB camera with a short USB packet, + so that's easy to detect. The frame buffers form a list that is filled + by the camera+USB controller and drained by the user process through + either read() or mmap(). + + The image buffer is the third scheme, in which frames are decompressed + and converted into planar format. For mmap() there is more than + one image buffer available. + + The frame buffers provide the image buffering. In case the user process + is a bit slow, this introduces lag and some undesired side-effects. + The problem arises when the frame buffer is full. I used to drop the last + frame, which makes the data in the queue stale very quickly. But dropping + the frame at the head of the queue proved to be a litte bit more difficult. + I tried a circular linked scheme, but this introduced more problems than + it solved. + + Because filling and draining are completely asynchronous processes, this + requires some fiddling with pointers and mutexes. + + Eventually, I came up with a system with 2 lists: an 'empty' frame list + and a 'full' frame list: + * Initially, all frame buffers but one are on the 'empty' list; the one + remaining buffer is our initial fill frame. + * If a frame is needed for filling, we try to take it from the 'empty' + list, unless that list is empty, in which case we take the buffer at + the head of the 'full' list. + * When our fill buffer has been filled, it is appended to the 'full' + list. + * If a frame is needed by read() or mmap(), it is taken from the head of + the 'full' list, handled, and then appended to the 'empty' list. If no + buffer is present on the 'full' list, we wait. + The advantage is that the buffer that is currently being decompressed/ + converted, is on neither list, and thus not in our way (any other scheme + I tried had the problem of old data lingering in the queue). + + Whatever strategy you choose, it always remains a tradeoff: with more + frame buffers the chances of a missed frame are reduced. On the other + hand, on slower machines it introduces lag because the queue will + always be full. + */ + +/** + \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. + */ +static inline int pwc_next_fill_frame(struct pwc_device *pdev) +{ + int ret; + unsigned long flags; + + ret = 0; + spin_lock_irqsave(&pdev->ptrlock, flags); + if (pdev->fill_frame != NULL) { + /* append to 'full' list */ + if (pdev->full_frames == NULL) { + pdev->full_frames = pdev->fill_frame; + pdev->full_frames_tail = pdev->full_frames; + } + else { + pdev->full_frames_tail->next = pdev->fill_frame; + pdev->full_frames_tail = pdev->fill_frame; + } + } + if (pdev->empty_frames != NULL) { + /* We have empty frames available. That's easy */ + pdev->fill_frame = pdev->empty_frames; + pdev->empty_frames = pdev->empty_frames->next; + } + else { + /* Hmm. Take it from the full list */ +#if PWC_DEBUG + /* sanity check */ + if (pdev->full_frames == NULL) { + Err("Neither empty or full frames available!\n"); + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return -EINVAL; + } +#endif + pdev->fill_frame = pdev->full_frames; + pdev->full_frames = pdev->full_frames->next; + ret = 1; + } + pdev->fill_frame->next = NULL; +#if PWC_DEBUG + Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); + pdev->fill_frame->sequence = pdev->sequence++; +#endif + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return ret; +} + + +/** + \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. + + If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. + */ +static void pwc_reset_buffers(struct pwc_device *pdev) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&pdev->ptrlock, flags); + pdev->full_frames = NULL; + pdev->full_frames_tail = NULL; + for (i = 0; i < default_fbufs; i++) { + pdev->fbuf[i].filled = 0; + if (i > 0) + pdev->fbuf[i].next = &pdev->fbuf[i - 1]; + else + pdev->fbuf->next = NULL; + } + pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; + pdev->empty_frames_tail = pdev->fbuf; + pdev->read_frame = NULL; + pdev->fill_frame = pdev->empty_frames; + pdev->empty_frames = pdev->empty_frames->next; + + pdev->image_read_pos = 0; + pdev->fill_image = 0; + spin_unlock_irqrestore(&pdev->ptrlock, flags); +} + + +/** + \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. + */ +static int pwc_handle_frame(struct pwc_device *pdev) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&pdev->ptrlock, flags); + /* First grab our read_frame; this is removed from all lists, so + we can release the lock after this without problems */ + if (pdev->read_frame != NULL) { + /* This can't theoretically happen */ + Err("Huh? Read frame still in use?\n"); + } + else { + if (pdev->full_frames == NULL) { + Err("Woops. No frames ready.\n"); + } + else { + pdev->read_frame = pdev->full_frames; + pdev->full_frames = pdev->full_frames->next; + pdev->read_frame->next = NULL; + } + + if (pdev->read_frame != NULL) { +#if PWC_DEBUG + Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); +#endif + /* Decompression is a lenghty process, so it's outside of the lock. + This gives the isoc_handler the opportunity to fill more frames + in the mean time. + */ + spin_unlock_irqrestore(&pdev->ptrlock, flags); + ret = pwc_decompress(pdev); + spin_lock_irqsave(&pdev->ptrlock, flags); + + /* We're done with read_buffer, tack it to the end of the empty buffer list */ + if (pdev->empty_frames == NULL) { + pdev->empty_frames = pdev->read_frame; + pdev->empty_frames_tail = pdev->empty_frames; + } + else { + pdev->empty_frames_tail->next = pdev->read_frame; + pdev->empty_frames_tail = pdev->read_frame; + } + pdev->read_frame = NULL; + } + } + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return ret; +} + +/** + \brief Advance pointers of image buffer (after each user request) +*/ +static inline void pwc_next_image(struct pwc_device *pdev) +{ + pdev->image_used[pdev->fill_image] = 0; + pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; +} + + +/* This gets called for the Isochronous pipe (video). This is done in + * interrupt time, so it has to be fast, not crash, and not stall. Neat. + */ +static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) +{ + struct pwc_device *pdev; + int i, fst, flen; + int awake; + struct pwc_frame_buf *fbuf; + unsigned char *fillptr = 0, *iso_buf = 0; + + awake = 0; + pdev = (struct pwc_device *)urb->context; + if (pdev == NULL) { + Err("isoc_handler() called with NULL device?!\n"); + return; + } +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("isoc_handler() called with bad magic!\n"); + return; + } +#endif + if (urb->status == -ENOENT || urb->status == -ECONNRESET) { + Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); + return; + } + if (urb->status != -EINPROGRESS && urb->status != 0) { + const char *errmsg; + + errmsg = "Unknown"; + switch(urb->status) { + case -ENOSR: errmsg = "Buffer error (overrun)"; break; + case -EPIPE: errmsg = "Stalled (device not responding)"; break; + case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; + case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; + case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; + case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; + } + Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); + /* Give up after a number of contiguous errors on the USB bus. + Appearantly something is wrong so we simulate an unplug event. + */ + if (++pdev->visoc_errors > MAX_ISOC_ERRORS) + { + Info("Too many ISOC errors, bailing out.\n"); + pdev->error_status = EIO; + awake = 1; + wake_up_interruptible(&pdev->frameq); + } + goto handler_end; // ugly, but practical + } + + fbuf = pdev->fill_frame; + if (fbuf == NULL) { + Err("pwc_isoc_handler without valid fill frame.\n"); + awake = 1; + goto handler_end; + } + else { + fillptr = fbuf->data + fbuf->filled; + } + + /* Reset ISOC error counter. We did get here, after all. */ + pdev->visoc_errors = 0; + + /* vsync: 0 = don't copy data + 1 = sync-hunt + 2 = synched + */ + /* Compact data */ + for (i = 0; i < urb->number_of_packets; i++) { + fst = urb->iso_frame_desc[i].status; + flen = urb->iso_frame_desc[i].actual_length; + iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (fst == 0) { + if (flen > 0) { /* if valid data... */ + if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ + pdev->vsync = 2; + + /* ...copy data to frame buffer, if possible */ + if (flen + fbuf->filled > pdev->frame_total_size) { + Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); + pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ + pdev->vframes_error++; + } + else { + memmove(fillptr, iso_buf, flen); + fillptr += flen; + } + } + fbuf->filled += flen; + } /* ..flen > 0 */ + + if (flen < pdev->vlast_packet_size) { + /* Shorter packet... We probably have the end of an image-frame; + wake up read() process and let select()/poll() do something. + Decompression is done in user time over there. + */ + if (pdev->vsync == 2) { + /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus + frames on the USB wire after an exposure change. This conditition is + however detected in the cam and a bit is set in the header. + */ + if (pdev->type == 730) { + unsigned char *ptr = (unsigned char *)fbuf->data; + + if (ptr[1] == 1 && ptr[0] & 0x10) { +#if PWC_DEBUG + Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); +#endif + pdev->drop_frames += 2; + pdev->vframes_error++; + } + if ((ptr[0] ^ pdev->vmirror) & 0x01) { + if (ptr[0] & 0x01) + Info("Snapshot button pressed.\n"); + else + Info("Snapshot button released.\n"); + } + if ((ptr[0] ^ pdev->vmirror) & 0x02) { + if (ptr[0] & 0x02) + Info("Image is mirrored.\n"); + else + Info("Image is normal.\n"); + } + pdev->vmirror = ptr[0] & 0x03; + /* Sometimes the trailer of the 730 is still sent as a 4 byte packet + after a short frame; this condition is filtered out specifically. A 4 byte + frame doesn't make sense anyway. + So we get either this sequence: + drop_bit set -> 4 byte frame -> short frame -> good frame + Or this one: + drop_bit set -> short frame -> good frame + So we drop either 3 or 2 frames in all! + */ + if (fbuf->filled == 4) + pdev->drop_frames++; + } + + /* In case we were instructed to drop the frame, do so silently. + The buffer pointers are not updated either (but the counters are reset below). + */ + if (pdev->drop_frames > 0) + pdev->drop_frames--; + else { + /* Check for underflow first */ + if (fbuf->filled < pdev->frame_total_size) { + Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); + pdev->vframes_error++; + } + else { + /* Send only once per EOF */ + awake = 1; /* delay wake_ups */ + + /* Find our next frame to fill. This will always succeed, since we + * nick a frame from either empty or full list, but if we had to + * take it from the full list, it means a frame got dropped. + */ + if (pwc_next_fill_frame(pdev)) { + pdev->vframes_dumped++; + if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { + if (pdev->vframes_dumped < 20) + Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); + if (pdev->vframes_dumped == 20) + Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); + } + } + fbuf = pdev->fill_frame; + } + } /* !drop_frames */ + pdev->vframe_count++; + } + fbuf->filled = 0; + fillptr = fbuf->data; + pdev->vsync = 1; + } /* .. flen < last_packet_size */ + pdev->vlast_packet_size = flen; + } /* ..status == 0 */ +#if PWC_DEBUG + /* This is normally not interesting to the user, unless you are really debugging something */ + else { + static int iso_error = 0; + iso_error++; + if (iso_error < 20) + Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); + } +#endif + } + +handler_end: + if (awake) + wake_up_interruptible(&pdev->frameq); + + urb->dev = pdev->udev; + i = usb_submit_urb(urb, GFP_ATOMIC); + if (i != 0) + Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); +} + + +static int pwc_isoc_init(struct pwc_device *pdev) +{ + struct usb_device *udev; + struct urb *urb; + int i, j, ret; + + struct usb_interface *intf; + struct usb_host_interface *idesc = NULL; + + if (pdev == NULL) + return -EFAULT; + if (pdev->iso_init) + return 0; + pdev->vsync = 0; + udev = pdev->udev; + + /* Get the current alternate interface, adjust packet size */ + if (!udev->actconfig) + return -EFAULT; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) + idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate]; +#else + intf = usb_ifnum_to_if(udev, 0); + if (intf) + idesc = usb_altnum_to_altsetting(intf, pdev->valternate); +#endif + + if (!idesc) + return -EFAULT; + + /* Search video endpoint */ + pdev->vmax_packet_size = -1; + for (i = 0; i < idesc->desc.bNumEndpoints; i++) + if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { + pdev->vmax_packet_size = idesc->endpoint[i].desc.wMaxPacketSize; + break; + } + + if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { + Err("Failed to find packet size for video endpoint in current alternate setting.\n"); + return -ENFILE; /* Odd error, that should be noticable */ + } + + /* Set alternate interface */ + ret = 0; + Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); + ret = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (ret < 0) + return ret; + + for (i = 0; i < MAX_ISO_BUFS; i++) { + urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); + if (urb == NULL) { + Err("Failed to allocate urb %d\n", i); + ret = -ENOMEM; + break; + } + pdev->sbuf[i].urb = urb; + Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); + } + if (ret) { + /* De-allocate in reverse order */ + while (i >= 0) { + if (pdev->sbuf[i].urb != NULL) + usb_free_urb(pdev->sbuf[i].urb); + pdev->sbuf[i].urb = NULL; + i--; + } + return ret; + } + + /* init URB structure */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + urb = pdev->sbuf[i].urb; + + urb->interval = 1; // devik + urb->dev = udev; + urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = pdev->sbuf[i].data; + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->complete = pwc_isoc_handler; + urb->context = pdev; + urb->start_frame = 0; + urb->number_of_packets = ISO_FRAMES_PER_DESC; + for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; + urb->iso_frame_desc[j].length = pdev->vmax_packet_size; + } + } + + /* link */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); + if (ret) + Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); + else + Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); + } + + /* All is done... */ + pdev->iso_init = 1; + Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); + return 0; +} + +static void pwc_isoc_cleanup(struct pwc_device *pdev) +{ + int i; + + Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); + if (pdev == NULL) + return; + + /* Unlinking ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = pdev->sbuf[i].urb; + if (urb != 0) { + if (pdev->iso_init) { + Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); + usb_unlink_urb(urb); + } + Trace(TRACE_MEMORY, "Freeing URB\n"); + usb_free_urb(urb); + pdev->sbuf[i].urb = NULL; + } + } + + /* Stop camera, but only if we are sure the camera is still there (unplug + is signalled by EPIPE) + */ + if (pdev->error_status && pdev->error_status != EPIPE) { + Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); + usb_set_interface(pdev->udev, 0, 0); + } + + pdev->iso_init = 0; + Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); +} + +int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) +{ + int ret, start; + + /* Stop isoc stuff */ + pwc_isoc_cleanup(pdev); + /* Reset parameters */ + pwc_reset_buffers(pdev); + /* Try to set video mode... */ + start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); + if (ret) { + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); + /* That failed... restore old mode (we know that worked) */ + start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + if (start) { + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); + } + } + if (start == 0) + { + if (pwc_isoc_init(pdev) < 0) + { + Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); + ret = -EAGAIN; /* let's try again, who knows if it works a second time */ + } + } + pdev->drop_frames++; /* try to avoid garbage during switch */ + return ret; /* Return original error code */ +} + + +/***************************************************************************/ +/* Video4Linux functions */ + +static int pwc_video_open(struct inode *inode, struct file *file) +{ + int i; + struct video_device *vdev = video_devdata(file); + struct pwc_device *pdev; + + Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); + + pdev = (struct pwc_device *)vdev->priv; + if (pdev == NULL) + BUG(); + if (pdev->vopen) + return -EBUSY; + + down(&pdev->modlock); + if (!pdev->usb_init) { + Trace(TRACE_OPEN, "Doing first time initialization.\n"); + pdev->usb_init = 1; + + if (pwc_trace & TRACE_OPEN) + { + /* Query sensor type */ + const char *sensor_type = NULL; + int ret; + + ret = pwc_get_cmos_sensor(pdev, &i); + if (ret >= 0) + { + switch(i) { + case 0x00: sensor_type = "Hyundai CMOS sensor"; break; + case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; + case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; + case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; + case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; + case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; + case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; + case 0x40: sensor_type = "UPA 1021 sensor"; break; + case 0x100: sensor_type = "VGA sensor"; break; + case 0x101: sensor_type = "PAL MR sensor"; break; + default: sensor_type = "unknown type of sensor"; break; + } + } + if (sensor_type != NULL) + Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + } + } + + /* Turn on camera */ + if (power_save) { + i = pwc_camera_power(pdev, 1); + if (i < 0) + Info("Failed to restore power to the camera! (%d)\n", i); + } + /* Set LED on/off time */ + if (pwc_set_leds(pdev, led_on, led_off) < 0) + Info("Failed to set LED on/off time.\n"); + + pwc_construct(pdev); /* set min/max sizes correct */ + + /* So far, so good. Allocate memory. */ + i = pwc_allocate_buffers(pdev); + if (i < 0) { + Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); + up(&pdev->modlock); + return i; + } + + /* Reset buffers & parameters */ + pwc_reset_buffers(pdev); + for (i = 0; i < default_mbufs; i++) + pdev->image_used[i] = 0; + pdev->vframe_count = 0; + pdev->vframes_dumped = 0; + pdev->vframes_error = 0; + pdev->visoc_errors = 0; + pdev->error_status = 0; +#if PWC_DEBUG + pdev->sequence = 0; +#endif + pwc_construct(pdev); /* set min/max sizes correct */ + + /* Set some defaults */ + pdev->vsnapshot = 0; + + /* Start iso pipe for video; first try the last used video size + (or the default one); if that fails try QCIF/10 or QSIF/10; + it that fails too, give up. + */ + i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); + if (i) { + Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); + if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); + else + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); + } + if (i) { + Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); + up(&pdev->modlock); + return i; + } + + i = pwc_isoc_init(pdev); + if (i) { + Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); + up(&pdev->modlock); + return i; + } + + pdev->vopen++; + file->private_data = vdev; + up(&pdev->modlock); + Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); + return 0; +} + +/* Note that all cleanup is done in the reverse order as in _open */ +static int pwc_video_close(struct inode *inode, struct file *file) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + int i; + + Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); + + pdev = (struct pwc_device *)vdev->priv; + if (pdev->vopen == 0) + Info("video_close() called on closed device?\n"); + + /* Dump statistics, but only if a reasonable amount of frames were + processed (to prevent endless log-entries in case of snap-shot + programs) + */ + if (pdev->vframe_count > 20) + Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); + + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_exit(); /* Timon & Kiara */ + break; + case 645: + case 646: + pwc_dec1_exit(); + break; + } + + pwc_isoc_cleanup(pdev); + pwc_free_buffers(pdev); + + /* Turn off LEDS and power down camera, but only when not unplugged */ + if (pdev->error_status != EPIPE) { + /* Turn LEDs off */ + if (pwc_set_leds(pdev, 0, 0) < 0) + Info("Failed to set LED on/off time.\n"); + if (power_save) { + i = pwc_camera_power(pdev, 0); + if (i < 0) + Err("Failed to power down camera (%d)\n", i); + } + } + pdev->vopen = 0; + Trace(TRACE_OPEN, "<< video_close()\n"); + return 0; +} + +/* + * FIXME: what about two parallel reads ???? + * ANSWER: Not supported. You can't open the device more than once, + despite what the V4L1 interface says. First, I don't see + the need, second there's no mechanism of alerting the + 2nd/3rd/... process of events like changing image size. + And I don't see the point of blocking that for the + 2nd/3rd/... process. + In multi-threaded environments reading parallel from any + device is tricky anyhow. + */ + +static ssize_t pwc_video_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + int noblock = file->f_flags & O_NONBLOCK; + DECLARE_WAITQUEUE(wait, current); + int bytes_to_read; + + Trace(TRACE_READ, "video_read(0x%p, %p, %d) called.\n", vdev, buf, count); + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + if (pdev->error_status) + return -pdev->error_status; /* Something happened, report what. */ + + /* In case we're doing partial reads, we don't have to wait for a frame */ + if (pdev->image_read_pos == 0) { + /* Do wait queueing according to the (doc)book */ + add_wait_queue(&pdev->frameq, &wait); + while (pdev->full_frames == NULL) { + /* Check for unplugged/etc. here */ + if (pdev->error_status) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -pdev->error_status ; + } + if (noblock) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -EWOULDBLOCK; + } + if (signal_pending(current)) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + + /* Decompress and release frame */ + if (pwc_handle_frame(pdev)) + return -EFAULT; + } + + Trace(TRACE_READ, "Copying data to user space.\n"); + if (pdev->vpalette == VIDEO_PALETTE_RAW) + bytes_to_read = pdev->frame_size; + else + bytes_to_read = pdev->view.size; + + /* copy bytes to user space; we allow for partial reads */ + if (count + pdev->image_read_pos > bytes_to_read) + count = bytes_to_read - pdev->image_read_pos; + if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) + return -EFAULT; + pdev->image_read_pos += count; + if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ + pdev->image_read_pos = 0; + pwc_next_image(pdev); + } + return count; +} + +static unsigned int pwc_video_poll(struct file *file, poll_table *wait) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + + poll_wait(file, &pdev->frameq, wait); + if (pdev->error_status) + return POLLERR; + if (pdev->full_frames != NULL) /* we have frames waiting */ + return (POLLIN | POLLRDNORM); + + return 0; +} + +static int pwc_video_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + DECLARE_WAITQUEUE(wait, current); + + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + + switch (cmd) { + /* Query cabapilities */ + case VIDIOCGCAP: + { + struct video_capability *caps = arg; + + strcpy(caps->name, vdev->name); + caps->type = VID_TYPE_CAPTURE; + caps->channels = 1; + caps->audios = 1; + caps->minwidth = pdev->view_min.x; + caps->minheight = pdev->view_min.y; + caps->maxwidth = pdev->view_max.x; + caps->maxheight = pdev->view_max.y; + break; + } + + /* Channel functions (simulate 1 channel) */ + case VIDIOCGCHAN: + { + struct video_channel *v = arg; + + if (v->channel != 0) + return -EINVAL; + v->flags = 0; + v->tuners = 0; + v->type = VIDEO_TYPE_CAMERA; + strcpy(v->name, "Webcam"); + return 0; + } + + case VIDIOCSCHAN: + { + /* The spec says the argument is an integer, but + the bttv driver uses a video_channel arg, which + makes sense becasue it also has the norm flag. + */ + struct video_channel *v = arg; + if (v->channel != 0) + return -EINVAL; + return 0; + } + + + /* Picture functions; contrast etc. */ + case VIDIOCGPICT: + { + struct video_picture *p = arg; + int val; + + val = pwc_get_brightness(pdev); + if (val >= 0) + p->brightness = val; + else + p->brightness = 0xffff; + val = pwc_get_contrast(pdev); + if (val >= 0) + p->contrast = val; + else + p->contrast = 0xffff; + /* Gamma, Whiteness, what's the difference? :) */ + val = pwc_get_gamma(pdev); + if (val >= 0) + p->whiteness = val; + else + p->whiteness = 0xffff; + val = pwc_get_saturation(pdev); + if (val >= 0) + p->colour = val; + else + p->colour = 0xffff; + p->depth = 24; + p->palette = pdev->vpalette; + p->hue = 0xFFFF; /* N/A */ + break; + } + + case VIDIOCSPICT: + { + struct video_picture *p = arg; + /* + * FIXME: Suppose we are mid read + ANSWER: No problem: the firmware of the camera + can handle brightness/contrast/etc + changes at _any_ time, and the palette + is used exactly once in the uncompress + routine. + */ + pwc_set_brightness(pdev, p->brightness); + pwc_set_contrast(pdev, p->contrast); + pwc_set_gamma(pdev, p->whiteness); + pwc_set_saturation(pdev, p->colour); + if (p->palette && p->palette != pdev->vpalette) { + switch (p->palette) { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + pdev->vpalette = p->palette; + return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + break; + default: + return -EINVAL; + break; + } + } + break; + } + + /* Window/size parameters */ + case VIDIOCGWIN: + { + struct video_window *vw = arg; + + vw->x = 0; + vw->y = 0; + vw->width = pdev->view.x; + vw->height = pdev->view.y; + vw->chromakey = 0; + vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | + (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); + break; + } + + case VIDIOCSWIN: + { + struct video_window *vw = arg; + int fps, snapshot, ret; + + fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; + snapshot = vw->flags & PWC_FPS_SNAPSHOT; + if (fps == 0) + fps = pdev->vframes; + if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) + return 0; + ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); + if (ret) + return ret; + break; + } + + /* We don't have overlay support (yet) */ + case VIDIOCGFBUF: + { + struct video_buffer *vb = arg; + + memset(vb,0,sizeof(*vb)); + break; + } + + /* mmap() functions */ + case VIDIOCGMBUF: + { + /* Tell the user program how much memory is needed for a mmap() */ + struct video_mbuf *vm = arg; + int i; + + memset(vm, 0, sizeof(*vm)); + vm->size = default_mbufs * pdev->len_per_image; + vm->frames = default_mbufs; /* double buffering should be enough for most applications */ + for (i = 0; i < default_mbufs; i++) + vm->offsets[i] = i * pdev->len_per_image; + break; + } + + case VIDIOCMCAPTURE: + { + /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ + struct video_mmap *vm = arg; + + Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); + if (vm->frame < 0 || vm->frame >= default_mbufs) + return -EINVAL; + + /* xawtv is nasty. It probes the available palettes + by setting a very small image size and trying + various palettes... The driver doesn't support + such small images, so I'm working around it. + */ + if (vm->format) + { + switch (vm->format) + { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + break; + default: + return -EINVAL; + break; + } + } + + if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && + (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { + int ret; + + Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); + ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + if (ret) + return ret; + } /* ... size mismatch */ + + /* FIXME: should we lock here? */ + if (pdev->image_used[vm->frame]) + return -EBUSY; /* buffer wasn't available. Bummer */ + pdev->image_used[vm->frame] = 1; + + /* Okay, we're done here. In the SYNC call we wait until a + frame comes available, then expand image into the given + buffer. + In contrast to the CPiA cam the Philips cams deliver a + constant stream, almost like a grabber card. Also, + we have separate buffers for the rawdata and the image, + meaning we can nearly always expand into the requested buffer. + */ + Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); + break; + } + + case VIDIOCSYNC: + { + /* The doc says: "Whenever a buffer is used it should + call VIDIOCSYNC to free this frame up and continue." + + The only odd thing about this whole procedure is + that MCAPTURE flags the buffer as "in use", and + SYNC immediately unmarks it, while it isn't + after SYNC that you know that the buffer actually + got filled! So you better not start a CAPTURE in + the same frame immediately (use double buffering). + This is not a problem for this cam, since it has + extra intermediate buffers, but a hardware + grabber card will then overwrite the buffer + you're working on. + */ + int *mbuf = arg; + int ret; + + Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); + + /* bounds check */ + if (*mbuf < 0 || *mbuf >= default_mbufs) + return -EINVAL; + /* check if this buffer was requested anyway */ + if (pdev->image_used[*mbuf] == 0) + return -EINVAL; + + /* Add ourselves to the frame wait-queue. + + FIXME: needs auditing for safety. + QUESTION: In what respect? I think that using the + frameq is safe now. + */ + add_wait_queue(&pdev->frameq, &wait); + while (pdev->full_frames == NULL) { + if (pdev->error_status) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -pdev->error_status; + } + + if (signal_pending(current)) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + + /* The frame is ready. Expand in the image buffer + requested by the user. I don't care if you + mmap() 5 buffers and request data in this order: + buffer 4 2 3 0 1 2 3 0 4 3 1 . . . + Grabber hardware may not be so forgiving. + */ + Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); + pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ + /* Decompress, etc */ + ret = pwc_handle_frame(pdev); + pdev->image_used[*mbuf] = 0; + if (ret) + return -EFAULT; + break; + } + + case VIDIOCGAUDIO: + { + struct video_audio *v = arg; + + strcpy(v->name, "Microphone"); + v->audio = -1; /* unknown audio minor */ + v->flags = 0; + v->mode = VIDEO_SOUND_MONO; + v->volume = 0; + v->bass = 0; + v->treble = 0; + v->balance = 0x8000; + v->step = 1; + break; + } + + case VIDIOCSAUDIO: + { + /* Dummy: nothing can be set */ + break; + } + + case VIDIOCGUNIT: + { + struct video_unit *vu = arg; + + vu->video = pdev->vdev->minor & 0x3F; + vu->audio = -1; /* not known yet */ + vu->vbi = -1; + vu->radio = -1; + vu->teletext = -1; + break; + } + default: + return pwc_ioctl(pdev, cmd, arg); + } /* ..switch */ + return 0; +} + +static int pwc_video_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); +} + + +static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end-vma->vm_start; + unsigned long page, pos; + + Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); + pdev = vdev->priv; + + vma->vm_flags |= VM_IO; + + pos = (unsigned long)pdev->image_data; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + +/***************************************************************************/ +/* USB functions */ + +/* This function gets called when a new device is plugged in or the usb core + * is loaded. + */ + +static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct pwc_device *pdev = NULL; + int vendor_id, product_id, type_id; + int i, hint; + int features = 0; + int video_nr = -1; /* default: use next available device */ + char serial_number[30], *name; + + /* Check if we can handle this device */ + Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", + udev->descriptor.idVendor, udev->descriptor.idProduct, + intf->altsetting->desc.bInterfaceNumber); + + /* the interfaces are probed one by one. We are only interested in the + video interface (0) now. + Interface 1 is the Audio Control, and interface 2 Audio itself. + */ + if (intf->altsetting->desc.bInterfaceNumber > 0) + return -ENODEV; + + vendor_id = udev->descriptor.idVendor; + product_id = udev->descriptor.idProduct; + + if (vendor_id == 0x0471) { + switch (product_id) { + case 0x0302: + Info("Philips PCA645VC USB webcam detected.\n"); + name = "Philips 645 webcam"; + type_id = 645; + break; + case 0x0303: + Info("Philips PCA646VC USB webcam detected.\n"); + name = "Philips 646 webcam"; + type_id = 646; + break; + case 0x0304: + Info("Askey VC010 type 2 USB webcam detected.\n"); + name = "Askey VC010 webcam"; + type_id = 646; + break; + case 0x0307: + Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + name = "Philips 675 webcam"; + type_id = 675; + break; + case 0x0308: + Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + name = "Philips 680 webcam"; + type_id = 680; + break; + case 0x030C: + Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + name = "Philips 690 webcam"; + type_id = 690; + break; + case 0x0310: + Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); + name = "Philips 730 webcam"; + type_id = 730; + break; + case 0x0311: + Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); + name = "Philips 740 webcam"; + type_id = 740; + break; + case 0x0312: + Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + name = "Philips 750 webcam"; + type_id = 750; + break; + case 0x0313: + Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); + name = "Philips 720K/40 webcam"; + type_id = 720; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x069A) { + switch(product_id) { + case 0x0001: + Info("Askey VC010 type 1 USB webcam detected.\n"); + name = "Askey VC010 webcam"; + type_id = 645; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x046d) { + switch(product_id) { + case 0x08b0: + Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); + name = "Logitech QuickCam Pro 3000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b1: + Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); + name = "Logitech QuickCam Notebook Pro"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b2: + Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); + name = "Logitech QuickCam Pro 4000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b3: + Info("Logitech QuickCam Zoom USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* CCD sensor */ + break; + case 0x08B4: + Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b5: + Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); + name = "Logitech QuickCam Orbit"; + type_id = 740; /* CCD sensor */ + features |= FEATURE_MOTOR_PANTILT; + break; + case 0x08b6: + case 0x08b7: + case 0x08b8: + Info("Logitech QuickCam detected (reserved ID).\n"); + name = "Logitech QuickCam (res.)"; + type_id = 730; /* Assuming CMOS */ + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x055d) { + /* I don't know the difference between the C10 and the C30; + I suppose the difference is the sensor, but both cameras + work equally well with a type_id of 675 + */ + switch(product_id) { + case 0x9000: + Info("Samsung MPC-C10 USB webcam detected.\n"); + name = "Samsung MPC-C10"; + type_id = 675; + break; + case 0x9001: + Info("Samsung MPC-C30 USB webcam detected.\n"); + name = "Samsung MPC-C30"; + type_id = 675; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x041e) { + switch(product_id) { + case 0x400c: + Info("Creative Labs Webcam 5 detected.\n"); + name = "Creative Labs Webcam 5"; + type_id = 730; + break; + case 0x4011: + Info("Creative Labs Webcam Pro Ex detected.\n"); + name = "Creative Labs Webcam Pro Ex"; + type_id = 740; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x04cc) { + switch(product_id) { + case 0x8116: + Info("Sotec Afina Eye USB webcam detected.\n"); + name = "Sotec Afina Eye"; + type_id = 730; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x06be) { + switch(product_id) { + case 0x8116: + /* This is essentially the same cam as the Sotec Afina Eye */ + Info("AME Co. Afina Eye USB webcam detected.\n"); + name = "AME Co. Afina Eye"; + type_id = 750; + break; + default: + return -ENODEV; + break; + } + + } + else if (vendor_id == 0x0d81) { + switch(product_id) { + case 0x1900: + Info("Visionite VCS-UC300 USB webcam detected.\n"); + name = "Visionite VCS-UC300"; + type_id = 740; /* CCD sensor */ + break; + case 0x1910: + Info("Visionite VCS-UM100 USB webcam detected.\n"); + name = "Visionite VCS-UM100"; + type_id = 730; /* CMOS sensor */ + break; + default: + return -ENODEV; + break; + } + } + else + return -ENODEV; /* Not any of the know types; but the list keeps growing. */ + + memset(serial_number, 0, 30); + usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); + Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); + + if (udev->descriptor.bNumConfigurations > 1) + Info("Warning: more than 1 configuration available.\n"); + + /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ + pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); + if (pdev == NULL) { + Err("Oops, could not allocate memory for pwc_device.\n"); + return -ENOMEM; + } + memset(pdev, 0, sizeof(struct pwc_device)); + pdev->type = type_id; + pdev->vsize = default_size; + pdev->vframes = default_fps; + strcpy(pdev->serial, serial_number); + pdev->features = features; + if (vendor_id == 0x046D && product_id == 0x08B5) + { + /* Logitech QuickCam Orbit + The ranges have been determined experimentally; they may differ from cam to cam. + Also, the exact ranges left-right and up-down are different for my cam + */ + pdev->angle_range.pan_min = -7000; + pdev->angle_range.pan_max = 7000; + pdev->angle_range.tilt_min = -3000; + pdev->angle_range.tilt_max = 2500; + } + + init_MUTEX(&pdev->modlock); + pdev->ptrlock = SPIN_LOCK_UNLOCKED; + + pdev->udev = udev; + init_waitqueue_head(&pdev->frameq); + pdev->vcompression = pwc_preferred_compression; + + /* Allocate video_device structure */ + pdev->vdev = video_device_alloc(); + if (pdev->vdev == 0) + { + Err("Err, cannot allocate video_device struture. Failing probe."); + kfree(pdev); + return -ENOMEM; + } + memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); + strcpy(pdev->vdev->name, name); + pdev->vdev->owner = THIS_MODULE; + video_set_drvdata(pdev->vdev, pdev); + + pdev->release = udev->descriptor.bcdDevice; + Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); + + /* Now search device_hint[] table for a match, so we can hint a node number. */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) { + if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && + (device_hint[hint].pdev == NULL)) { + /* so far, so good... try serial number */ + if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { + /* match! */ + video_nr = device_hint[hint].device_node; + Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); + break; + } + } + } + + pdev->vdev->release = video_device_release; + i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); + if (i < 0) { + Err("Failed to register as video device (%d).\n", i); + video_device_release(pdev->vdev); /* Drip... drip... drip... */ + kfree(pdev); /* Oops, no memory leaks please */ + return -EIO; + } + else { + Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); + } + + /* occupy slot */ + if (hint < MAX_DEV_HINTS) + device_hint[hint].pdev = pdev; + + Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); + usb_set_intfdata (intf, pdev); + return 0; +} + +/* The user janked out the cable... */ +static void usb_pwc_disconnect(struct usb_interface *intf) +{ + struct pwc_device *pdev; + int hint; + + lock_kernel(); + pdev = usb_get_intfdata (intf); + usb_set_intfdata (intf, NULL); + if (pdev == NULL) { + Err("pwc_disconnect() Called without private pointer.\n"); + goto disconnect_out; + } + if (pdev->udev == NULL) { + Err("pwc_disconnect() already called for %p\n", pdev); + goto disconnect_out; + } + if (pdev->udev != interface_to_usbdev(intf)) { + Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); + goto disconnect_out; + } +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); + goto disconnect_out; + } +#endif + + /* We got unplugged; this is signalled by an EPIPE error code */ + if (pdev->vopen) { + Info("Disconnected while webcam is in use!\n"); + pdev->error_status = EPIPE; + } + + /* Alert waiting processes */ + wake_up_interruptible(&pdev->frameq); + /* Wait until device is closed */ + while (pdev->vopen) + schedule(); + /* Device is now closed, so we can safely unregister it */ + Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); + video_unregister_device(pdev->vdev); + + /* Free memory (don't set pdev to 0 just yet) */ + kfree(pdev); + +disconnect_out: + /* search device_hint[] table if we occupy a slot, by any chance */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) + if (device_hint[hint].pdev == pdev) + device_hint[hint].pdev = NULL; + + unlock_kernel(); +} + + +/* *grunt* We have to do atoi ourselves :-( */ +static int pwc_atoi(const char *s) +{ + int k = 0; + + k = 0; + while (*s != '\0' && *s >= '0' && *s <= '9') { + k = 10 * k + (*s - '0'); + s++; + } + return k; +} + + +/* + * Initialization code & module stuff + */ + +static char *size = NULL; +static int fps = 0; +static int fbufs = 0; +static int mbufs = 0; +static int trace = -1; +static int compression = -1; +static int leds[2] = { -1, -1 }; +static char *dev_hint[MAX_DEV_HINTS] = { }; + +MODULE_PARM(size, "s"); +MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); +MODULE_PARM(fps, "i"); +MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); +MODULE_PARM(fbufs, "i"); +MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); +MODULE_PARM(mbufs, "i"); +MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); +MODULE_PARM(trace, "i"); +MODULE_PARM_DESC(trace, "For debugging purposes"); +MODULE_PARM(power_save, "i"); +MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); +MODULE_PARM(compression, "i"); +MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); +MODULE_PARM(leds, "2i"); +MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); +MODULE_PARM(dev_hint, "0-20s"); +MODULE_PARM_DESC(dev_hint, "Device node hints"); + +MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); +MODULE_AUTHOR("Luc Saillard "); +MODULE_LICENSE("GPL"); + +static int __init usb_pwc_init(void) +{ + int i, sz; + char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; + + Info("Philips webcam module version " PWC_VERSION " loaded.\n"); + Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); + Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); + Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); + + if (fps) { + if (fps < 4 || fps > 30) { + Err("Framerate out of bounds (4-30).\n"); + return -EINVAL; + } + default_fps = fps; + Info("Default framerate set to %d.\n", default_fps); + } + + if (size) { + /* string; try matching with array */ + for (sz = 0; sz < PSZ_MAX; sz++) { + if (!strcmp(sizenames[sz], size)) { /* Found! */ + default_size = sz; + break; + } + } + if (sz == PSZ_MAX) { + Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); + return -EINVAL; + } + Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); + } + if (mbufs) { + if (mbufs < 1 || mbufs > MAX_IMAGES) { + Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); + return -EINVAL; + } + default_mbufs = mbufs; + Info("Number of image buffers set to %d.\n", default_mbufs); + } + if (fbufs) { + if (fbufs < 2 || fbufs > MAX_FRAMES) { + Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); + return -EINVAL; + } + default_fbufs = fbufs; + Info("Number of frame buffers set to %d.\n", default_fbufs); + } + if (trace >= 0) { + Info("Trace options: 0x%04x\n", trace); + pwc_trace = trace; + } + if (compression >= 0) { + if (compression > 3) { + Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); + return -EINVAL; + } + pwc_preferred_compression = compression; + Info("Preferred compression set to %d.\n", pwc_preferred_compression); + } + if (power_save) + Info("Enabling power save on open/close.\n"); + if (leds[0] >= 0) + led_on = leds[0]; + if (leds[1] >= 0) + led_off = leds[1]; + + /* Big device node whoopla. Basicly, it allows you to assign a + device node (/dev/videoX) to a camera, based on its type + & serial number. The format is [type[.serialnumber]:]node. + + Any camera that isn't matched by these rules gets the next + available free device node. + */ + for (i = 0; i < MAX_DEV_HINTS; i++) { + char *s, *colon, *dot; + + /* This loop also initializes the array */ + device_hint[i].pdev = NULL; + s = dev_hint[i]; + if (s != NULL && *s != '\0') { + device_hint[i].type = -1; /* wildcard */ + strcpy(device_hint[i].serial_number, "*"); + + /* parse string: chop at ':' & '/' */ + colon = dot = s; + while (*colon != '\0' && *colon != ':') + colon++; + while (*dot != '\0' && *dot != '.') + dot++; + /* Few sanity checks */ + if (*dot != '\0' && dot > colon) { + Err("Malformed camera hint: the colon must be after the dot.\n"); + return -EINVAL; + } + + if (*colon == '\0') { + /* No colon */ + if (*dot != '\0') { + Err("Malformed camera hint: no colon + device node given.\n"); + return -EINVAL; + } + else { + /* No type or serial number specified, just a number. */ + device_hint[i].device_node = pwc_atoi(s); + } + } + else { + /* There's a colon, so we have at least a type and a device node */ + device_hint[i].type = pwc_atoi(s); + device_hint[i].device_node = pwc_atoi(colon + 1); + if (*dot != '\0') { + /* There's a serial number as well */ + int k; + + dot++; + k = 0; + while (*dot != ':' && k < 29) { + device_hint[i].serial_number[k++] = *dot; + dot++; + } + device_hint[i].serial_number[k] = '\0'; + } + } +#if PWC_DEBUG + Debug("device_hint[%d]:\n", i); + Debug(" type : %d\n", device_hint[i].type); + Debug(" serial# : %s\n", device_hint[i].serial_number); + Debug(" node : %d\n", device_hint[i].device_node); +#endif + } + else + device_hint[i].type = 0; /* not filled */ + } /* ..for MAX_DEV_HINTS */ + + Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); + return usb_register(&pwc_driver); +} + +static void __exit usb_pwc_exit(void) +{ + Trace(TRACE_MODULE, "Deregistering driver.\n"); + usb_deregister(&pwc_driver); + Info("Philips webcam module removed.\n"); +} + +module_init(usb_pwc_init); +module_exit(usb_pwc_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-ioctl.h linux-2.6.9/drivers/usb/media/pwc/pwc-ioctl.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-ioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-ioctl.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,292 @@ +#ifndef PWC_IOCTL_H +#define PWC_IOCTL_H + +/* (C) 2001-2004 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + +/* This is pwc-ioctl.h belonging to PWC 8.12.1 + It contains structures and defines to communicate from user space + directly to the driver. + */ + +/* + Changes + 2001/08/03 Alvarado Added ioctl constants to access methods for + changing white balance and red/blue gains + 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE + 2003/12/13 Nemosft Unv. Some modifications to make interfacing to + PWCX easier + */ + +/* These are private ioctl() commands, specific for the Philips webcams. + They contain functions not found in other webcams, and settings not + specified in the Video4Linux API. + + The #define names are built up like follows: + VIDIOC VIDeo IOCtl prefix + PWC Philps WebCam + G optional: Get + S optional: Set + ... the function + */ + + + /* Enumeration of image sizes */ +#define PSZ_SQCIF 0x00 +#define PSZ_QSIF 0x01 +#define PSZ_QCIF 0x02 +#define PSZ_SIF 0x03 +#define PSZ_CIF 0x04 +#define PSZ_VGA 0x05 +#define PSZ_MAX 6 + + +/* The frame rate is encoded in the video_window.flags parameter using + the upper 16 bits, since some flags are defined nowadays. The following + defines provide a mask and shift to filter out this value. + + In 'Snapshot' mode the camera freezes its automatic exposure and colour + balance controls. + */ +#define PWC_FPS_SHIFT 16 +#define PWC_FPS_MASK 0x00FF0000 +#define PWC_FPS_FRMASK 0x003F0000 +#define PWC_FPS_SNAPSHOT 0x00400000 + + +/* structure for transfering x & y coordinates */ +struct pwc_coord +{ + int x, y; /* guess what */ + int size; /* size, or offset */ +}; + + +/* Used with VIDIOCPWCPROBE */ +struct pwc_probe +{ + char name[32]; + int type; +}; + +struct pwc_serial +{ + char serial[30]; /* String with serial number. Contains terminating 0 */ +}; + +/* pwc_whitebalance.mode values */ +#define PWC_WB_INDOOR 0 +#define PWC_WB_OUTDOOR 1 +#define PWC_WB_FL 2 +#define PWC_WB_MANUAL 3 +#define PWC_WB_AUTO 4 + +/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). + Set mode to one of the PWC_WB_* values above. + *red and *blue are the respective gains of these colour components inside + the camera; range 0..65535 + When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; + otherwise undefined. + 'read_red' and 'read_blue' are read-only. +*/ +struct pwc_whitebalance +{ + int mode; + int manual_red, manual_blue; /* R/W */ + int read_red, read_blue; /* R/O */ +}; + +/* + 'control_speed' and 'control_delay' are used in automatic whitebalance mode, + and tell the camera how fast it should react to changes in lighting, and + with how much delay. Valid values are 0..65535. +*/ +struct pwc_wb_speed +{ + int control_speed; + int control_delay; + +}; + +/* Used with VIDIOCPWC[SG]LED */ +struct pwc_leds +{ + int led_on; /* Led on-time; range = 0..25000 */ + int led_off; /* Led off-time; range = 0..25000 */ +}; + +/* Image size (used with GREALSIZE) */ +struct pwc_imagesize +{ + int width; + int height; +}; + +/* Defines and structures for Motorized Pan & Tilt */ +#define PWC_MPT_PAN 0x01 +#define PWC_MPT_TILT 0x02 +#define PWC_MPT_TIMEOUT 0x04 /* for status */ + +/* Set angles; when absolute != 0, the angle is absolute and the + driver calculates the relative offset for you. This can only + be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns + absolute angles. + */ +struct pwc_mpt_angles +{ + int absolute; /* write-only */ + int pan; /* degrees * 100 */ + int tilt; /* degress * 100 */ +}; + +/* Range of angles of the camera, both horizontally and vertically. + */ +struct pwc_mpt_range +{ + int pan_min, pan_max; /* degrees * 100 */ + int tilt_min, tilt_max; +}; + +struct pwc_mpt_status +{ + int status; + int time_pan; + int time_tilt; +}; + + +/* This is used for out-of-kernel decompression. With it, you can get + all the necessary information to initialize and use the decompressor + routines in standalone applications. + */ +struct pwc_video_command +{ + int type; /* camera type (645, 675, 730, etc.) */ + int release; /* release number */ + + int size; /* one of PSZ_* */ + int alternate; + int command_len; /* length of USB video command */ + unsigned char command_buf[13]; /* Actual USB video command */ + int bandlength; /* >0 = compressed */ + int frame_size; /* Size of one (un)compressed frame */ +}; + +/* Flags for PWCX subroutines. Not all modules honour all flags. */ +#define PWCX_FLAG_PLANAR 0x0001 +#define PWCX_FLAG_BAYER 0x0008 + + +/* IOCTL definitions */ + + /* Restore user settings */ +#define VIDIOCPWCRUSER _IO('v', 192) + /* Save user settings */ +#define VIDIOCPWCSUSER _IO('v', 193) + /* Restore factory settings */ +#define VIDIOCPWCFACTORY _IO('v', 194) + + /* You can manipulate the compression factor. A compression preference of 0 + means use uncompressed modes when available; 1 is low compression, 2 is + medium and 3 is high compression preferred. Of course, the higher the + compression, the lower the bandwidth used but more chance of artefacts + in the image. The driver automatically chooses a higher compression when + the preferred mode is not available. + */ + /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ +#define VIDIOCPWCSCQUAL _IOW('v', 195, int) + /* Get preferred compression quality */ +#define VIDIOCPWCGCQUAL _IOR('v', 195, int) + + +/* Retrieve serial number of camera */ +#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) + + /* This is a probe function; since so many devices are supported, it + becomes difficult to include all the names in programs that want to + check for the enhanced Philips stuff. So in stead, try this PROBE; + it returns a structure with the original name, and the corresponding + Philips type. + To use, fill the structure with zeroes, call PROBE and if that succeeds, + compare the name with that returned from VIDIOCGCAP; they should be the + same. If so, you can be assured it is a Philips (OEM) cam and the type + is valid. + */ +#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) + + /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ +#define VIDIOCPWCSAGC _IOW('v', 200, int) + /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCGAGC _IOR('v', 200, int) + /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) + + /* Color compensation (Auto White Balance) */ +#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) +#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) + + /* Auto WB speed */ +#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) +#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) + + /* LEDs on/off/blink; int range 0..65535 */ +#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) +#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) + + /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ +#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) +#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) + + /* Backlight compensation; 0 = off, otherwise on */ +#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) +#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) + + /* Flickerless mode; = 0 off, otherwise on */ +#define VIDIOCPWCSFLICKER _IOW('v', 208, int) +#define VIDIOCPWCGFLICKER _IOR('v', 208, int) + + /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ +#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) +#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) + + /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ +#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) + + /* Motorized pan & tilt functions */ +#define VIDIOCPWCMPTRESET _IOW('v', 211, int) +#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) +#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) +#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) +#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) + + /* Get the USB set-video command; needed for initializing libpwcx */ +#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) +struct pwc_table_init_buffer { + int len; + char *buffer; + +}; +#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-kiara.c linux-2.6.9/drivers/usb/media/pwc/pwc-kiara.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-kiara.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-kiara.c 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,891 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + + +/* This tables contains entries for the 730/740/750 (Kiara) camera, with + 4 different qualities (no compression, low, medium, high). + It lists the bandwidth requirements for said mode by its alternate interface + number. An alternate of 0 means that the mode is unavailable. + + There are 6 * 4 * 4 entries: + 6 different resolutions subqcif, qsif, qcif, sif, cif, vga + 6 framerates: 5, 10, 15, 20, 25, 30 + 4 compression modi: none, low, medium, high + + When an uncompressed mode is not available, the next available compressed mode + will be chosen (unless the decompressor is absent). Sometimes there are only + 1 or 2 compressed modes available; in that case entries are duplicated. +*/ + + +#include "pwc-kiara.h" +#include "pwc-uncompress.h" + +const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = +{ + /* SQCIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* QSIF */ + { + /* 5 fps */ + { + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + }, + /* 10 fps */ + { + {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + }, + /* 15 fps */ + { + {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, + {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, + {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, + {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, + }, + /* 20 fps */ + { + {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, + {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, + {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, + {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, + }, + /* 25 fps */ + { + {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, + {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, + {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, + {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, + }, + /* 30 fps */ + { + {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, + {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, + {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, + {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, + }, + }, + /* QCIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* SIF */ + { + /* 5 fps */ + { + {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, + {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, + {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, + {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, + }, + /* 10 fps */ + { + {0, }, + {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, + {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, + {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, + }, + /* 15 fps */ + { + {0, }, + {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, + {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, + {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, + }, + /* 20 fps */ + { + {0, }, + {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, + {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, + {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, + }, + /* 25 fps */ + { + {0, }, + {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, + {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, + {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, + }, + /* 30 fps */ + { + {0, }, + {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, + {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, + {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, + }, + }, + /* CIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* VGA */ + { + /* 5 fps */ + { + {0, }, + {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, + {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, + {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, + }, + /* 10 fps */ + { + {0, }, + {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, + {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, + {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, + }, + /* 15 fps */ + { + {0, }, + {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, + {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, + {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, +}; + + +/* + * Rom table for kiara chips + * + * 32 roms tables (one for each resolution ?) + * 2 tables per roms (one for each passes) (Y, and U&V) + * 128 bytes per passes + */ + +const unsigned int KiaraRomTable [8][2][16][8] = +{ + { /* version 0 */ + { /* version 0, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x0000124a,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009292,0x00009292,0x00009493,0x000124db}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x0000a493,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x000124db,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 0, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000001,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000049,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009252,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009292,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009292, + 0x00009492,0x00009493,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009252,0x00009493, + 0x000126dc,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 1 */ + { /* version 1, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009252,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009252, + 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 1, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000049,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000000}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000049,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x0000924a,0x0000924a, + 0x00009492,0x00009493,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 2 */ + { /* version 2, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x0000a49b}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 2, passes 1 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x0000a49b,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 3 */ + { /* version 3, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 3, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 4 */ + { /* version 4, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009252,0x00009493, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 4, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000049,0x00000049,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00000249,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 5 */ + { /* version 5, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 5, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x00009252,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 6 */ + { /* version 6, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000126db, + 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 6, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 7 */ + { /* version 7, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x000124db}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 7, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x00009492,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + } +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-kiara.h linux-2.6.9/drivers/usb/media/pwc/pwc-kiara.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-kiara.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-kiara.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,45 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + +/* Entries for the Kiara (730/740/750) camera */ + +#ifndef PWC_KIARA_H +#define PWC_KIARA_H + +#include "pwc-ioctl.h" + +struct Kiara_table_entry +{ + char alternate; /* USB alternate interface */ + unsigned short packetsize; /* Normal packet size */ + unsigned short bandlength; /* Bandlength when decompressing */ + unsigned char mode[12]; /* precomputed mode settings for cam */ +}; + +const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; +const extern unsigned int KiaraRomTable[8][2][16][8]; + +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-misc.c linux-2.6.9/drivers/usb/media/pwc/pwc-misc.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-misc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-misc.c 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,140 @@ +/* Linux driver for Philips webcam + Various miscellaneous functions and tables. + (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 "pwc.h" + +struct pwc_coord pwc_image_sizes[PSZ_MAX] = +{ + { 128, 96, 0 }, + { 160, 120, 0 }, + { 176, 144, 0 }, + { 320, 240, 0 }, + { 352, 288, 0 }, + { 640, 480, 0 }, +}; + +/* x,y -> PSZ_ */ +int pwc_decode_size(struct pwc_device *pdev, int width, int height) +{ + int i, find; + + /* Make sure we don't go beyond our max size. + NB: we have different limits for RAW and normal modes. In case + you don't have the decompressor loaded or use RAW mode, + the maximum viewable size is smaller. + */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + if (width > pdev->abs_max.x || height > pdev->abs_max.y) + { + Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); + return -1; + } + } + else + { + if (width > pdev->view_max.x || height > pdev->view_max.y) + { + Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n"); + return -1; + } + } + + /* Find the largest size supported by the camera that fits into the + requested size. + */ + find = -1; + for (i = 0; i < PSZ_MAX; i++) { + if (pdev->image_mask & (1 << i)) { + if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) + find = i; + } + } + return find; +} + +/* initialize variables depending on type and decompressor*/ +void pwc_construct(struct pwc_device *pdev) +{ + switch(pdev->type) { + case 645: + case 646: + pdev->view_min.x = 128; + pdev->view_min.y = 96; + pdev->view_max.x = 352; + pdev->view_max.y = 288; + pdev->abs_max.x = 352; + pdev->abs_max.y = 288; + pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; + pdev->vcinterface = 2; + pdev->vendpoint = 4; + pdev->frame_header_size = 0; + pdev->frame_trailer_size = 0; + break; + case 675: + case 680: + case 690: + pdev->view_min.x = 128; + pdev->view_min.y = 96; + /* Anthill bug #38: PWC always reports max size, even without PWCX */ + pdev->view_max.x = 640; + pdev->view_max.y = 480; + pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; + pdev->abs_max.x = 640; + pdev->abs_max.y = 480; + pdev->vcinterface = 3; + pdev->vendpoint = 4; + pdev->frame_header_size = 0; + pdev->frame_trailer_size = 0; + break; + case 720: + case 730: + case 740: + case 750: + pdev->view_min.x = 160; + pdev->view_min.y = 120; + pdev->view_max.x = 640; + pdev->view_max.y = 480; + pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; + pdev->abs_max.x = 640; + pdev->abs_max.y = 480; + pdev->vcinterface = 3; + pdev->vendpoint = 5; + pdev->frame_header_size = TOUCAM_HEADER_SIZE; + pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; + break; + } + Debug("type = %d\n",pdev->type); + pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ + pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; + pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; + /* length of image, in YUV format; always allocate enough memory. */ + pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-nala.h linux-2.6.9/drivers/usb/media/pwc/pwc-nala.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-nala.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-nala.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,66 @@ + /* SQCIF */ + { + {0, 0, {0x04, 0x01, 0x03}}, + {8, 0, {0x05, 0x01, 0x03}}, + {7, 0, {0x08, 0x01, 0x03}}, + {7, 0, {0x0A, 0x01, 0x03}}, + {6, 0, {0x0C, 0x01, 0x03}}, + {5, 0, {0x0F, 0x01, 0x03}}, + {4, 0, {0x14, 0x01, 0x03}}, + {3, 0, {0x18, 0x01, 0x03}}, + }, + /* QSIF */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, + /* QCIF */ + { + {0, 0, {0x04, 0x01, 0x02}}, + {8, 0, {0x05, 0x01, 0x02}}, + {7, 0, {0x08, 0x01, 0x02}}, + {6, 0, {0x0A, 0x01, 0x02}}, + {5, 0, {0x0C, 0x01, 0x02}}, + {4, 0, {0x0F, 0x01, 0x02}}, + {1, 0, {0x14, 0x01, 0x02}}, + {1, 0, {0x18, 0x01, 0x02}}, + }, + /* SIF */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, + /* CIF */ + { + {4, 0, {0x04, 0x01, 0x01}}, + {7, 1, {0x05, 0x03, 0x01}}, + {6, 1, {0x08, 0x03, 0x01}}, + {4, 1, {0x0A, 0x03, 0x01}}, + {3, 1, {0x0C, 0x03, 0x01}}, + {2, 1, {0x0F, 0x03, 0x01}}, + {0}, + {0}, + }, + /* VGA */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-timon.c linux-2.6.9/drivers/usb/media/pwc/pwc-timon.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-timon.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-timon.c 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,1446 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + + +/* This tables contains entries for the 675/680/690 (Timon) camera, with + 4 different qualities (no compression, low, medium, high). + It lists the bandwidth requirements for said mode by its alternate interface + number. An alternate of 0 means that the mode is unavailable. + + There are 6 * 4 * 4 entries: + 6 different resolutions subqcif, qsif, qcif, sif, cif, vga + 6 framerates: 5, 10, 15, 20, 25, 30 + 4 compression modi: none, low, medium, high + + When an uncompressed mode is not available, the next available compressed mode + will be chosen (unless the decompressor is absent). Sometimes there are only + 1 or 2 compressed modes available; in that case entries are duplicated. +*/ + +#include "pwc-timon.h" + +const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = +{ + /* SQCIF */ + { + /* 5 fps */ + { + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + }, + /* 10 fps */ + { + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + }, + /* 15 fps */ + { + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + }, + /* 20 fps */ + { + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + }, + /* 25 fps */ + { + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + }, + /* 30 fps */ + { + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + }, + }, + /* QSIF */ + { + /* 5 fps */ + { + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + }, + /* 10 fps */ + { + {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + }, + /* 15 fps */ + { + {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, + {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + }, + /* 20 fps */ + { + {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, + {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, + }, + /* 25 fps */ + { + {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, + {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, + {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, + {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, + {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, + }, + }, + /* QCIF */ + { + /* 5 fps */ + { + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + }, + /* 10 fps */ + { + {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, + {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, + }, + /* 15 fps */ + { + {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, + {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, + }, + /* 20 fps */ + { + {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, + {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, + {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, + }, + /* 25 fps */ + { + {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, + {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, + {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, + {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, + {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, + }, + }, + /* SIF */ + { + /* 5 fps */ + { + {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, + {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, + {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, + {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, + {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, + {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, + {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, + {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, + {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, + {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, + }, + /* 25 fps */ + { + {0, }, + {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, + {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, + {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, + {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, + {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, + }, + }, + /* CIF */ + { + /* 5 fps */ + { + {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, + {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, + {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, + {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, + {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, + {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, + {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, + {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, + {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, + {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, + }, + /* 25 fps */ + { + {0, }, + {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, + {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, + {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, + {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, + {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, + }, + }, + /* VGA */ + { + /* 5 fps */ + { + {0, }, + {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, + {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, + {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, + {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, + {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, + {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, + {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, +}; + +/* + * 16 versions: + * 2 tables (one for Y, and one for U&V) + * 16 levels of details per tables + * 8 blocs + */ + +const unsigned int TimonRomTable [16][2][16][8] = +{ + { /* version 0 */ + { /* version 0, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000001,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000001, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000009,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x0000124a,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 0, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000001,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000001, + 0x00000001,0x00000009,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000009,0x00000049,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000009,0x00000049,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 1 */ + { /* version 1, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000009,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 1, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000001,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000049,0x00000249,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009252,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 2 */ + { /* version 2, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009252,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009252, + 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 2, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000049,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000000}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000049,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x0000924a,0x0000924a, + 0x00009492,0x00009493,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 3 */ + { /* version 3, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009252, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009292,0x0000a49b,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 3, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00000049,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009252,0x00009292,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009292, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 4 */ + { /* version 4, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x0000a49b}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 4, passes 1 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x0000a49b,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 5 */ + { /* version 5, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000126dc,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 5, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x00009493,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x000124db,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009493,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 6 */ + { /* version 6, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 6, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 7 */ + { /* version 7, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x0002496e}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x0001c96e,0x0002496e}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x0002496d,0x00025bb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 7, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000136e4,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00012492,0x000126db, + 0x0001b724,0x0001b925,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 8 */ + { /* version 8, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000126dc,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x00024b76,0x00024b77}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x00024b76,0x00025bbf}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0001c92d,0x00024b76,0x00025bbf}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 8, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x0001b724,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x0002496d,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 9 */ + { /* version 9, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009252,0x00009493, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 9, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000049,0x00000049,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00000249,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 10 */ + { /* version 10, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000126dc,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0002496d,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 10, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00000249,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x00009493,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009493,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x00009492,0x00009493,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009493,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 11 */ + { /* version 11, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 11, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x00009252,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 12 */ + { /* version 12, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000126db, + 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 12, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 13 */ + { /* version 13, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x000124db}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 13, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x00009492,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 14 */ + { /* version 14, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000136e4,0x0001b725,0x000124db}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000126dc,0x0001b724,0x0001b92d,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x0002496d,0x00024b76,0x00024b77}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 14, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000136e4,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 15 */ + { /* version 15, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x0002496d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x00024b6d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 15, passes 1 */ + {0x00000000,0x00000000,0x0000924a,0x0000924a, + 0x00009292,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000124db,0x0001b724,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x0001b724,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x0001b724,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000136db, + 0x0001b724,0x0001b724,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001c924,0x0001b724,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001c924,0x0001b724,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b724,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x00024924,0x0002496d,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-timon.h linux-2.6.9/drivers/usb/media/pwc/pwc-timon.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-timon.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-timon.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,61 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + + + +/* This tables contains entries for the 675/680/690 (Timon) camera, with + 4 different qualities (no compression, low, medium, high). + It lists the bandwidth requirements for said mode by its alternate interface + number. An alternate of 0 means that the mode is unavailable. + + There are 6 * 4 * 4 entries: + 6 different resolutions subqcif, qsif, qcif, sif, cif, vga + 6 framerates: 5, 10, 15, 20, 25, 30 + 4 compression modi: none, low, medium, high + + When an uncompressed mode is not available, the next available compressed mode + will be chosen (unless the decompressor is absent). Sometimes there are only + 1 or 2 compressed modes available; in that case entries are duplicated. +*/ + +#ifndef PWC_TIMON_H +#define PWC_TIMON_H + +#include "pwc-ioctl.h" + +struct Timon_table_entry +{ + char alternate; /* USB alternate interface */ + unsigned short packetsize; /* Normal packet size */ + unsigned short bandlength; /* Bandlength when decompressing */ + unsigned char mode[13]; /* precomputed mode settings for cam */ +}; + +const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; +const extern unsigned int TimonRomTable [16][2][16][8]; + + +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-uncompress.c linux-2.6.9/drivers/usb/media/pwc/pwc-uncompress.c --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-uncompress.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-uncompress.c 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,147 @@ +/* Linux driver for Philips webcam + Decompression frontend. + (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 "pwc.h" +#include "pwc-uncompress.h" +#include "pwc-dec1.h" +#include "pwc-dec23.h" + +int pwc_decompress(struct pwc_device *pdev) +{ + struct pwc_frame_buf *fbuf; + int n, line, col, stride; + void *yuv, *image; + u16 *src; + u16 *dsty, *dstu, *dstv; + + if (pdev == NULL) + return -EFAULT; +#if defined(__KERNEL__) && defined(PWC_MAGIC) + if (pdev->magic != PWC_MAGIC) { + Err("pwc_decompress(): magic failed.\n"); + return -EFAULT; + } +#endif + + fbuf = pdev->read_frame; + if (fbuf == NULL) + return -EFAULT; + image = pdev->image_ptr[pdev->fill_image]; + if (!image) + return -EFAULT; + + yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ + + /* Raw format; that's easy... */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + memcpy(image, yuv, pdev->frame_size); + return 0; + } + + if (pdev->vbandlength == 0) { + /* Uncompressed mode. We copy the data into the output buffer, + using the viewport size (which may be larger than the image + size). Unfortunately we have to do a bit of byte stuffing + to get the desired output format/size. + */ + /* + * We do some byte shuffling here to go from the + * native format to YUV420P. + */ + src = (u16 *)yuv; + n = pdev->view.x * pdev->view.y; + + /* offset in Y plane */ + stride = pdev->view.x * pdev->offset.y + pdev->offset.x; + dsty = (u16 *)(image + stride); + + /* offsets in U/V planes */ + stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; + dstu = (u16 *)(image + n + stride); + dstv = (u16 *)(image + n + n / 4 + stride); + + /* increment after each line */ + stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ + + for (line = 0; line < pdev->image.y; line++) { + for (col = 0; col < pdev->image.x; col += 4) { + *dsty++ = *src++; + *dsty++ = *src++; + if (line & 1) + *dstv++ = *src++; + else + *dstu++ = *src++; + } + dsty += stride; + if (line & 1) + dstv += (stride >> 1); + else + dstu += (stride >> 1); + } + } + else { + /* Compressed; the decompressor routines will write the data + in planar format immediately. + */ + int flags; + + flags = PWCX_FLAG_PLANAR; + if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) + { + printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); + flags |= PWCX_FLAG_BAYER; + return -ENXIO; /* No such device or address: missing decompressor */ + } + + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_decompress(&pdev->image, &pdev->view, &pdev->offset, + yuv, image, + flags, + pdev->decompress_data, pdev->vbandlength); + break; + case 645: + case 646: + /* TODO & FIXME */ + return -ENXIO; /* No such device or address: missing decompressor */ + break; + } + } + return 0; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-uncompress.h linux-2.6.9/drivers/usb/media/pwc/pwc-uncompress.h --- linux.vanilla-2.6.9/drivers/usb/media/pwc/pwc-uncompress.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/pwc-uncompress.h 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,41 @@ +/* (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + 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 +*/ + +/* This file is the bridge between the kernel module and the plugin; it + describes the structures and datatypes used in both modules. Any + significant change should be reflected by increasing the + pwc_decompressor_version major number. + */ +#ifndef PWC_UNCOMPRESS_H +#define PWC_UNCOMPRESS_H + +#include + +#include "pwc-ioctl.h" + +/* from pwc-dec.h */ +#define PWCX_FLAG_PLANAR 0x0001 +/* */ + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/pwc/philips.txt linux-2.6.9/drivers/usb/media/pwc/philips.txt --- linux.vanilla-2.6.9/drivers/usb/media/pwc/philips.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/pwc/philips.txt 2004-10-21 00:07:14.000000000 +0100 @@ -0,0 +1,236 @@ +This file contains some additional information for the Philips and OEM webcams. +E-mail: webcam@smcc.demon.nl Last updated: 2004-01-19 +Site: http://www.smcc.demon.nl/webcam/ + +As of this moment, the following cameras are supported: + * Philips PCA645 + * Philips PCA646 + * Philips PCVC675 + * Philips PCVC680 + * Philips PCVC690 + * Philips PCVC720/40 + * Philips PCVC730 + * Philips PCVC740 + * Philips PCVC750 + * Askey VC010 + * Creative Labs Webcam 5 + * Creative Labs Webcam Pro Ex + * Logitech QuickCam 3000 Pro + * Logitech QuickCam 4000 Pro + * Logitech QuickCam Notebook Pro + * Logitech QuickCam Zoom + * Logitech QuickCam Orbit + * Logitech QuickCam Sphere + * Samsung MPC-C10 + * Samsung MPC-C30 + * Sotec Afina Eye + * AME CU-001 + * Visionite VCS-UM100 + * Visionite VCS-UC300 + +The main webpage for the Philips driver is at the address above. It contains +a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin +contains decompression routines that allow you to use higher image sizes and +framerates; in addition the webcam uses less bandwidth on the USB bus (handy +if you want to run more than 1 camera simultaneously). These routines fall +under a NDA, and may therefor not be distributed as source; however, its use +is completely optional. + +You can build this code either into your kernel, or as a module. I recommend +the latter, since it makes troubleshooting a lot easier. The built-in +microphone is supported through the USB Audio class. + +When you load the module you can set some default settings for the +camera; some programs depend on a particular image-size or -format and +don't know how to set it properly in the driver. The options are: + +size + Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or + 'vga', for an image size of resp. 128x96, 160x120, 176x144, + 320x240, 352x288 and 640x480 (of course, only for those cameras that + support these resolutions). + +fps + Specifies the desired framerate. Is an integer in the range of 4-30. + +fbufs + This paramter specifies the number of internal buffers to use for storing + frames from the cam. This will help if the process that reads images from + the cam is a bit slow or momentarely busy. However, on slow machines it + only introduces lag, so choose carefully. The default is 3, which is + reasonable. You can set it between 2 and 5. + +mbufs + This is an integer between 1 and 10. It will tell the module the number of + buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. + The default is 2, which is adequate for most applications (double + buffering). + + Should you experience a lot of 'Dumping frame...' messages during + grabbing with a tool that uses mmap(), you might want to increase if. + However, it doesn't really buffer images, it just gives you a bit more + slack when your program is behind. But you need a multi-threaded or + forked program to really take advantage of these buffers. + + The absolute maximum is 10, but don't set it too high! Every buffer takes + up 460 KB of RAM, so unless you have a lot of memory setting this to + something more than 4 is an absolute waste. This memory is only + allocated during open(), so nothing is wasted when the camera is not in + use. + +power_save + When power_save is enabled (set to 1), the module will try to shut down + the cam on close() and re-activate on open(). This will save power and + turn off the LED. Not all cameras support this though (the 645 and 646 + don't have power saving at all), and some models don't work either (they + will shut down, but never wake up). Consider this experimental. By + default this option is disabled. + +compression (only useful with the plugin) + With this option you can control the compression factor that the camera + uses to squeeze the image through the USB bus. You can set the + parameter between 0 and 3: + 0 = prefer uncompressed images; if the requested mode is not available + in an uncompressed format, the driver will silently switch to low + compression. + 1 = low compression. + 2 = medium compression. + 3 = high compression. + + High compression takes less bandwidth of course, but it could also + introduce some unwanted artefacts. The default is 2, medium compression. + See the FAQ on the website for an overview of which modes require + compression. + + The compression parameter does not apply to the 645 and 646 cameras + and OEM models derived from those (only a few). Most cams honour this + parameter. + +leds + This settings takes 2 integers, that define the on/off time for the LED + (in milliseconds). One of the interesting things that you can do with + this is let the LED blink while the camera is in use. This: + + leds=500,500 + + will blink the LED once every second. But with: + + leds=0,0 + + the LED never goes on, making it suitable for silent surveillance. + + By default the camera's LED is on solid while in use, and turned off + when the camera is not used anymore. + + This parameter works only with the ToUCam range of cameras (720, 730, 740, + 750) and OEMs. For other cameras this command is silently ignored, and + the LED cannot be controlled. + + Finally: this parameters does not take effect UNTIL the first time you + open the camera device. Until then, the LED remains on. + +dev_hint + A long standing problem with USB devices is their dynamic nature: you + never know what device a camera gets assigned; it depends on module load + order, the hub configuration, the order in which devices are plugged in, + and the phase of the moon (i.e. it can be random). With this option you + can give the driver a hint as to what video device node (/dev/videoX) it + should use with a specific camera. This is also handy if you have two + cameras of the same model. + + A camera is specified by its type (the number from the camera model, + like PCA645, PCVC750VC, etc) and optionally the serial number (visible + in /proc/bus/usb/devices). A hint consists of a string with the following + format: + + [type[.serialnumber]:]node + + The square brackets mean that both the type and the serialnumber are + optional, but a serialnumber cannot be specified without a type (which + would be rather pointless). The serialnumber is separated from the type + by a '.'; the node number by a ':'. + + This somewhat cryptic syntax is best explained by a few examples: + + dev_hint=3,5 The first detected cam gets assigned + /dev/video3, the second /dev/video5. Any + other cameras will get the first free + available slot (see below). + + dev_hint=645:1,680:2 The PCA645 camera will get /dev/video1, + and a PCVC680 /dev/video2. + + dev_hint=645.0123:3,645.4567:0 The PCA645 camera with serialnumber + 0123 goes to /dev/video3, the same + camera model with the 4567 serial + gets /dev/video0. + + dev_hint=750:1,4,5,6 The PCVC750 camera will get /dev/video1, the + next 3 Philips cams will use /dev/video4 + through /dev/video6. + + Some points worth knowing: + - Serialnumbers are case sensitive and must be written full, including + leading zeroes (it's treated as a string). + - If a device node is already occupied, registration will fail and + the webcam is not available. + - You can have up to 64 video devices; be sure to make enough device + nodes in /dev if you want to spread the numbers (this does not apply + to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA). + - If a camera does not match any dev_hint, it will simply get assigned + the first available device node, just as it used to be. + +trace + In order to better detect problems, it is now possible to turn on a + 'trace' of some of the calls the module makes; it logs all items in your + kernel log at debug level. + + The trace variable is a bitmask; each bit represents a certain feature. + If you want to trace something, look up the bit value(s) in the table + below, add the values together and supply that to the trace variable. + + Value Value Description Default + (dec) (hex) + 1 0x1 Module initialization; this will log messages On + while loading and unloading the module + + 2 0x2 probe() and disconnect() traces On + + 4 0x4 Trace open() and close() calls Off + + 8 0x8 read(), mmap() and associated ioctl() calls Off + + 16 0x10 Memory allocation of buffers, etc. Off + + 32 0x20 Showing underflow, overflow and Dumping frame On + messages + + 64 0x40 Show viewport and image sizes Off + + 128 0x80 PWCX debugging Off + + For example, to trace the open() & read() fuctions, sum 8 + 4 = 12, + so you would supply trace=12 during insmod or modprobe. If + you want to turn the initialization and probing tracing off, set trace=0. + The default value for trace is 35 (0x23). + + + +Example: + + # modprobe pwc size=cif fps=15 power_save=1 + +The fbufs, mbufs and trace parameters are global and apply to all connected +cameras. Each camera has its own set of buffers. + +size and fps only specify defaults when you open() the device; this is to +accommodate some tools that don't set the size. You can change these +settings after open() with the Video4Linux ioctl() calls. The default of +defaults is QCIF size at 10 fps. + +The compression parameter is semiglobal; it sets the initial compression +preference for all camera's, but this parameter can be set per camera with +the VIDIOCPWCSCQUAL ioctl() call. + +All parameters are optional. + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/misc/usbtest.c linux-2.6.9/drivers/usb/misc/usbtest.c --- linux.vanilla-2.6.9/drivers/usb/misc/usbtest.c 2004-10-20 23:16:59.000000000 +0100 +++ linux-2.6.9/drivers/usb/misc/usbtest.c 2004-11-15 16:06:00.000000000 +0000 @@ -1355,7 +1355,7 @@ "iso test, %lu errors\n", ctx->errors); complete (&ctx->done); - } else + } done: spin_unlock(&ctx->lock); } @@ -1457,8 +1457,10 @@ status = usb_submit_urb (urbs [i], SLAB_ATOMIC); if (status < 0) { ERROR (dev, "submit iso[%d], error %d\n", i, status); - if (i == 0) + if (i == 0) { + spin_unlock_irq (&context.lock); goto fail; + } simple_free_urb (urbs [i]); context.pending--; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/serial/io_edgeport.c linux-2.6.9/drivers/usb/serial/io_edgeport.c --- linux.vanilla-2.6.9/drivers/usb/serial/io_edgeport.c 2004-10-20 23:17:00.000000000 +0100 +++ linux-2.6.9/drivers/usb/serial/io_edgeport.c 2004-12-01 21:16:53.000000000 +0000 @@ -2745,9 +2745,12 @@ static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size) { int i; - for (i = 0; i < unicode_size; ++i) { + + if (unicode_size <= 0) + return; + + for (i = 0; i < unicode_size; ++i) string[i] = (char)(le16_to_cpu(unicode[i])); - } string[unicode_size] = 0x00; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/serial/kl5kusb105.c linux-2.6.9/drivers/usb/serial/kl5kusb105.c --- linux.vanilla-2.6.9/drivers/usb/serial/kl5kusb105.c 2004-10-20 22:33:09.000000000 +0100 +++ linux-2.6.9/drivers/usb/serial/kl5kusb105.c 2004-11-15 16:02:37.000000000 +0000 @@ -782,9 +782,11 @@ switch (cflag & CSIZE) { case CS5: dbg("%s - 5 bits/byte not supported", __FUNCTION__); + spin_unlock_irqrestore (&priv->lock, flags); return ; case CS6: dbg("%s - 6 bits/byte not supported", __FUNCTION__); + spin_unlock_irqrestore (&priv->lock, flags); return ; case CS7: priv->cfg.databits = kl5kusb105a_dtb_7; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/serial/visor.c linux-2.6.9/drivers/usb/serial/visor.c --- linux.vanilla-2.6.9/drivers/usb/serial/visor.c 2004-10-20 22:33:09.000000000 +0100 +++ linux-2.6.9/drivers/usb/serial/visor.c 2004-11-25 22:28:18.000000000 +0000 @@ -381,10 +381,17 @@ .read_bulk_callback = visor_read_bulk_callback, }; +struct visor_private { + spinlock_t lock; + int bytes_in; + int bytes_out; + int outstanding_urbs; +}; -static int bytes_in; -static int bytes_out; +/* number of outstanding urbs to prevent userspace DoS from happening */ +#define URB_UPPER_LIMIT 42 +static int stats; /****************************************************************************** * Handspring Visor specific driver functions @@ -392,6 +399,8 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; + struct visor_private *priv = usb_get_serial_port_data(port); + unsigned long flags; int result = 0; dbg("%s - port %d", __FUNCTION__, port->number); @@ -402,8 +411,11 @@ return -ENODEV; } - bytes_in = 0; - bytes_out = 0; + spin_lock_irqsave(&priv->lock, flags); + priv->bytes_in = 0; + priv->bytes_out = 0; + priv->outstanding_urbs = 0; + spin_unlock_irqrestore(&priv->lock, flags); /* * Force low_latency on so that our tty_push actually forces the data @@ -441,6 +453,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) { + struct visor_private *priv = usb_get_serial_port_data(port); unsigned char *transfer_buffer; dbg("%s - port %d", __FUNCTION__, port->number); @@ -461,20 +474,31 @@ kfree (transfer_buffer); } - /* Uncomment the following line if you want to see some statistics in your syslog */ - /* dev_info (&port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */ + if (stats) + dev_info(&port->dev, "Bytes In = %d Bytes Out = %d\n", + priv->bytes_in, priv->bytes_out); } static int visor_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { + struct visor_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; struct urb *urb; unsigned char *buffer; + unsigned long flags; int status; dbg("%s - port %d", __FUNCTION__, port->number); + spin_lock_irqsave(&priv->lock, flags); + if (priv->outstanding_urbs > URB_UPPER_LIMIT) { + spin_unlock_irqrestore(&priv->lock, flags); + dev_dbg(&port->dev, "write limit hit\n"); + return 0; + } + spin_unlock_irqrestore(&priv->lock, flags); + buffer = kmalloc (count, GFP_ATOMIC); if (!buffer) { dev_err(&port->dev, "out of memory\n"); @@ -514,7 +538,10 @@ count = status; kfree (buffer); } else { - bytes_out += count; + spin_lock_irqsave(&priv->lock, flags); + ++priv->outstanding_urbs; + priv->bytes_out += count; + spin_unlock_irqrestore(&priv->lock, flags); } /* we are done with this urb, so let the host driver @@ -555,6 +582,8 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct visor_private *priv = usb_get_serial_port_data(port); + unsigned long flags; /* free up the transfer buffer, as usb_free_urb() does not do this */ kfree (urb->transfer_buffer); @@ -565,6 +594,10 @@ dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); + spin_lock_irqsave(&priv->lock, flags); + --priv->outstanding_urbs; + spin_unlock_irqrestore(&priv->lock, flags); + schedule_work(&port->work); } @@ -572,8 +605,10 @@ static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct tty_struct *tty; + struct visor_private *priv = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; + struct tty_struct *tty; + unsigned long flags; int i; int result; @@ -598,7 +633,9 @@ } tty_flip_buffer_push(tty); } - bytes_in += urb->actual_length; + spin_lock_irqsave(&priv->lock, flags); + priv->bytes_in += urb->actual_length; + spin_unlock_irqrestore(&priv->lock, flags); /* Continue trying to always read */ usb_fill_bulk_urb (port->read_urb, port->serial->dev, @@ -833,6 +870,22 @@ return num_ports; } +static int generic_startup(struct usb_serial *serial) +{ + struct visor_private *priv; + int i; + + for (i = 0; i < serial->num_ports; ++i) { + priv = kmalloc (sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + memset (priv, 0x00, sizeof(*priv)); + spin_lock_init(&priv->lock); + usb_set_serial_port_data(serial->port[i], priv); + } + return 0; +} + static int clie_3_5_startup (struct usb_serial *serial) { struct device *dev = &serial->dev->dev; @@ -872,7 +925,7 @@ return -EIO; } - return 0; + return generic_startup(serial); } static int treo_attach (struct usb_serial *serial) @@ -884,7 +937,7 @@ if (!((serial->dev->descriptor.idVendor == HANDSPRING_VENDOR_ID) || (serial->dev->descriptor.idVendor == KYOCERA_VENDOR_ID)) || (serial->num_interrupt_in == 0)) - return 0; + goto generic_startup; dbg("%s", __FUNCTION__); @@ -911,7 +964,8 @@ COPY_PORT(serial->port[1], swap_port); kfree(swap_port); - return 0; +generic_startup: + return generic_startup(serial); } static int clie_5_attach (struct usb_serial *serial) @@ -932,7 +986,7 @@ /* port 0 now uses the modified endpoint Address */ serial->port[0]->bulk_out_endpointAddress = serial->port[1]->bulk_out_endpointAddress; - return 0; + return generic_startup(serial); } static void visor_shutdown (struct usb_serial *serial) @@ -1088,8 +1142,11 @@ module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); +module_param(stats, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(stats, "Enables statistics or not"); module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified vendor ID"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified product ID"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/serial/whiteheat.c linux-2.6.9/drivers/usb/serial/whiteheat.c --- linux.vanilla-2.6.9/drivers/usb/serial/whiteheat.c 2004-10-20 23:17:01.000000000 +0100 +++ linux-2.6.9/drivers/usb/serial/whiteheat.c 2004-11-15 16:03:34.000000000 +0000 @@ -1119,11 +1119,11 @@ command_port->write_urb->transfer_buffer_length = datasize + 1; command_port->write_urb->dev = port->serial->dev; retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL); - spin_unlock_irqrestore(&command_info->lock, flags); if (retval) { dbg("%s - submit urb failed", __FUNCTION__); goto exit; } + spin_unlock_irqrestore(&command_info->lock, flags); /* wait for the command to complete */ wait_event_interruptible_timeout(command_info->wait_command, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/storage/scsiglue.c linux-2.6.9/drivers/usb/storage/scsiglue.c --- linux.vanilla-2.6.9/drivers/usb/storage/scsiglue.c 2004-10-20 23:17:02.000000000 +0100 +++ linux-2.6.9/drivers/usb/storage/scsiglue.c 2004-11-25 21:03:27.000000000 +0000 @@ -158,7 +158,7 @@ US_DEBUGP("%s called\n", __FUNCTION__); srb->host_scribble = (unsigned char *)us; - /* enqueue the command */ + /* check for state-transition errors */ if (us->sm_state != US_STATE_IDLE || us->srb != NULL) { printk(KERN_ERR USB_STORAGE "Error in %s: " "state = %d, us->srb = %p\n", @@ -166,10 +166,17 @@ return SCSI_MLQUEUE_HOST_BUSY; } + /* fail the command if we are disconnecting */ + if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + US_DEBUGP("Fail command during disconnect\n"); + srb->result = DID_NO_CONNECT << 16; + done(srb); + return 0; + } + + /* enqueue the command and wake up the control thread */ srb->scsi_done = done; us->srb = srb; - - /* wake up the process task */ up(&(us->sema)); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/storage/unusual_devs.h linux-2.6.9/drivers/usb/storage/unusual_devs.h --- linux.vanilla-2.6.9/drivers/usb/storage/unusual_devs.h 2004-10-20 23:17:03.000000000 +0100 +++ linux-2.6.9/drivers/usb/storage/unusual_devs.h 2004-11-08 17:15:30.000000000 +0000 @@ -424,6 +424,13 @@ 0 ), #endif +/* Reported by Avi Kivity */ +UNUSUAL_DEV( 0x05ac, 0x1203, 0x0001, 0x0001, + "Apple", + "iPod", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + #ifdef CONFIG_USB_STORAGE_JUMPSHOT UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, "Lexar", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/binfmt_aout.c linux-2.6.9/fs/binfmt_aout.c --- linux.vanilla-2.6.9/fs/binfmt_aout.c 2004-10-20 23:17:12.000000000 +0100 +++ linux-2.6.9/fs/binfmt_aout.c 2004-11-15 16:28:09.000000000 +0000 @@ -43,13 +43,18 @@ .min_coredump = PAGE_SIZE }; -static void set_brk(unsigned long start, unsigned long end) +#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) + +static int set_brk(unsigned long start, unsigned long end) { start = PAGE_ALIGN(start); end = PAGE_ALIGN(end); - if (end <= start) - return; - do_brk(start, end - start); + if (end > start) { + unsigned long addr = do_brk(start, end - start); + if (BAD_ADDR(addr)) + return addr; + } + return 0; } /* @@ -413,7 +418,11 @@ beyond_if: set_binfmt(&aout_format); - set_brk(current->mm->start_brk, current->mm->brk); + retval = set_brk(current->mm->start_brk, current->mm->brk); + if (retval < 0) { + send_sig(SIGKILL, current, 0); + return retval; + } retval = setup_arg_pages(bprm, EXSTACK_DEFAULT); if (retval < 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/binfmt_elf.c linux-2.6.9/fs/binfmt_elf.c --- linux.vanilla-2.6.9/fs/binfmt_elf.c 2004-10-20 23:17:12.000000000 +0100 +++ linux-2.6.9/fs/binfmt_elf.c 2004-11-17 19:40:40.000000000 +0000 @@ -335,9 +335,12 @@ goto out; retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size); - error = retval; - if (retval < 0) + error = -EIO; + if (retval != size) { + if (retval < 0) + error = retval; goto out_close; + } eppnt = elf_phdata; for (i=0; ie_phnum; i++, eppnt++) { @@ -532,8 +535,11 @@ goto out; retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, (char *) elf_phdata, size); - if (retval < 0) + if (retval != size) { + if (retval >= 0) + retval = -EIO; goto out_free_ph; + } files = current->files; /* Refcounted so ok */ retval = unshare_files(); @@ -570,7 +576,8 @@ */ retval = -ENOMEM; - if (elf_ppnt->p_filesz > PATH_MAX) + if (elf_ppnt->p_filesz > PATH_MAX || + elf_ppnt->p_filesz == 0) goto out_free_file; elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); @@ -580,8 +587,16 @@ retval = kernel_read(bprm->file, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz); - if (retval < 0) + if (retval != elf_ppnt->p_filesz) { + if (retval >= 0) + retval = -EIO; goto out_free_interp; + } + /* make sure path is NULL terminated */ + retval = -EINVAL; + if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') + goto out_free_interp; + /* If the program interpreter is one of these two, * then assume an iBCS2 image. Otherwise assume * a native linux image. @@ -616,8 +631,11 @@ if (IS_ERR(interpreter)) goto out_free_interp; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); - if (retval < 0) + if (retval != BINPRM_BUF_SIZE) { + if (retval >= 0) + retval = -EIO; goto out_free_dentry; + } /* Get the exec headers */ loc->interp_ex = *((struct exec *) bprm->buf); @@ -776,8 +794,10 @@ } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); - if (BAD_ADDR(error)) - continue; + if (BAD_ADDR(error)) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } if (!load_addr_set) { load_addr_set = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/bio.c linux-2.6.9/fs/bio.c --- linux.vanilla-2.6.9/fs/bio.c 2004-10-20 23:17:12.000000000 +0100 +++ linux-2.6.9/fs/bio.c 2004-12-01 21:18:18.000000000 +0000 @@ -461,11 +461,10 @@ bmd->userptr = (void __user *) uaddr; + ret = -ENOMEM; bio = bio_alloc(GFP_KERNEL, end - start); - if (!bio) { - bio_free_map_data(bmd); - return ERR_PTR(-ENOMEM); - } + if (!bio) + goto out_bmd; bio->bi_rw |= (!write_to_vm << BIO_RW); @@ -519,6 +518,8 @@ __free_page(bvec->bv_page); bio_put(bio); +out_bmd: + bio_free_map_data(bmd); return ERR_PTR(ret); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/buffer.c linux-2.6.9/fs/buffer.c --- linux.vanilla-2.6.9/fs/buffer.c 2004-10-20 23:17:12.000000000 +0100 +++ linux-2.6.9/fs/buffer.c 2004-12-11 00:03:17.000000000 +0000 @@ -506,6 +506,7 @@ struct buffer_head *bh; struct buffer_head *head; struct page *page; + int all_mapped = 1; index = block >> (PAGE_CACHE_SHIFT - bd_inode->i_blkbits); page = find_get_page(bd_mapping, index); @@ -523,14 +524,23 @@ get_bh(bh); goto out_unlock; } + if (!buffer_mapped(bh)) + all_mapped = 0; bh = bh->b_this_page; } while (bh != head); - printk("__find_get_block_slow() failed. " - "block=%llu, b_blocknr=%llu\n", - (unsigned long long)block, (unsigned long long)bh->b_blocknr); - printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size); - printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits); + /* we might be here because some of the buffers on this page are + * not mapped. This is due to various races between + * file io on the block device and getblk. It gets dealt with + * elsewhere, don't buffer_error if we had some unmapped buffers + */ + if (all_mapped) { + printk("__find_get_block_slow() failed. " + "block=%llu, b_blocknr=%llu\n", + (unsigned long long)block, (unsigned long long)bh->b_blocknr); + printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size); + printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits); + } out_unlock: spin_unlock(&bd_mapping->private_lock); page_cache_release(page); @@ -1172,18 +1182,16 @@ { struct buffer_head *head = page_buffers(page); struct buffer_head *bh = head; - unsigned int b_state; - - b_state = 1 << BH_Mapped; - if (PageUptodate(page)) - b_state |= 1 << BH_Uptodate; + int uptodate = PageUptodate(page); do { - if (!(bh->b_state & (1 << BH_Mapped))) { + if (!buffer_mapped(bh)) { init_buffer(bh, NULL, NULL); bh->b_bdev = bdev; bh->b_blocknr = block; - bh->b_state = b_state; + if (uptodate) + set_buffer_uptodate(bh); + set_buffer_mapped(bh); } block++; bh = bh->b_this_page; @@ -1212,8 +1220,10 @@ if (page_has_buffers(page)) { bh = page_buffers(page); - if (bh->b_size == size) + if (bh->b_size == size) { + init_page_buffers(page, bdev, block, size); return page; + } if (!try_to_free_buffers(page)) goto failed; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/dcache.c linux-2.6.9/fs/dcache.c --- linux.vanilla-2.6.9/fs/dcache.c 2004-10-20 23:17:15.000000000 +0100 +++ linux-2.6.9/fs/dcache.c 2004-11-17 19:50:15.000000000 +0000 @@ -278,14 +278,18 @@ /** * d_find_alias - grab a hashed alias of inode * @inode: inode in question + * @want_discon: flag, used by d_splice_alias, to request + * that only a DISCONNECTED alias be returned. * - * If inode has a hashed alias - acquire the reference to alias and - * return it. Otherwise return NULL. Notice that if inode is a directory - * there can be only one alias and it can be unhashed only if it has - * no children. + * If inode has a hashed alias, or is a directory and has any alias, + * acquire the reference to alias and return it. Otherwise return NULL. + * Notice that if inode is a directory there can be only one alias and + * it can be unhashed only if it has no children, or if it is the root + * of a filesystem. * * If the inode has a DCACHE_DISCONNECTED alias, then prefer - * any other hashed alias over that one. + * any other hashed alias over that one unless @want_discon is set, + * in which case only return a DCACHE_DISCONNECTED alias. */ static struct dentry * __d_find_alias(struct inode *inode, int want_discon) @@ -300,7 +304,7 @@ next = tmp->next; prefetch(next); alias = list_entry(tmp, struct dentry, d_alias); - if (!d_unhashed(alias)) { + if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { if (alias->d_flags & DCACHE_DISCONNECTED) discon_alias = alias; else if (!want_discon) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/exec.c linux-2.6.9/fs/exec.c --- linux.vanilla-2.6.9/fs/exec.c 2004-10-20 23:17:15.000000000 +0100 +++ linux-2.6.9/fs/exec.c 2004-12-01 21:08:51.000000000 +0000 @@ -56,6 +56,10 @@ int core_uses_pid; char core_pattern[65] = "core"; +int suid_dumpable = 0; + +EXPORT_SYMBOL(suid_dumpable); + /* The maximal length of core_pattern is also specified in sysctl.c */ static struct linux_binfmt *formats; @@ -341,7 +345,7 @@ unsigned long stack_base; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; - int i; + int i, ret; long arg_size; #ifdef CONFIG_STACK_GROWSUP @@ -432,7 +436,11 @@ mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_flags |= mm->def_flags; mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7]; - insert_vm_struct(mm, mpnt); + if ((ret = insert_vm_struct(mm, mpnt))) { + up_write(&mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt); + return ret; + } mm->stack_vm = mm->total_vm = vma_pages(mpnt); } @@ -845,6 +853,9 @@ if (current->euid == current->uid && current->egid == current->gid) current->mm->dumpable = 1; + else + current->mm->dumpable = suid_dumpable; + name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -861,7 +872,7 @@ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) || (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; /* An exec changes our domain. We are no longer part of the thread group */ @@ -994,7 +1005,7 @@ */ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) { - int try,retval=0; + int try,retval; struct linux_binfmt *fmt; #ifdef __alpha__ /* handle /sbin/loader.. */ @@ -1038,6 +1049,7 @@ /* kernel module loader fixup */ /* so we don't try to load run modprobe in kernel space. */ set_fs(USER_DS); + retval = -ENOENT; for (try=0; try<2; try++) { read_lock(&binfmt_lock); for (fmt = formats ; fmt ; fmt = fmt->next) { @@ -1378,7 +1390,9 @@ struct inode * inode; struct file * file; int retval = 0; - + int fsuid = current->fsuid; + int flag = 0; + binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; @@ -1387,6 +1401,17 @@ up_write(&mm->mmap_sem); goto fail; } + + /* + * We cannot trust fsuid as being the "true" uid of the + * process nor do we know its entire history. We only know it + * was tainted so we dump it as root in mode 2. + */ + if (mm->dumpable == 2) /* Setuid core dump mode */ + { + flag = O_EXCL; /* Stop rewrite attacks */ + current->fsuid = 0; /* Dump root private */ + } mm->dumpable = 0; init_completion(&mm->core_done); current->signal->group_exit = 1; @@ -1403,7 +1428,7 @@ lock_kernel(); format_corename(corename, core_pattern, signr); unlock_kernel(); - file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600); + file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600); if (IS_ERR(file)) goto fail_unlock; inode = file->f_dentry->d_inode; @@ -1427,6 +1452,7 @@ close_fail: filp_close(file, NULL); fail_unlock: + current->fsuid = fsuid; complete_all(&mm->core_done); fail: return retval; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/fat/inode.c linux-2.6.9/fs/fat/inode.c --- linux.vanilla-2.6.9/fs/fat/inode.c 2004-10-20 23:17:17.000000000 +0100 +++ linux-2.6.9/fs/fat/inode.c 2004-10-31 16:35:13.000000000 +0000 @@ -1003,6 +1003,8 @@ /* all is as it should be */ } else if (media == 0xf8 && FAT_FIRST_ENT(sb, 0xfe) == first) { /* bad, reported on pc9800 */ + } else if (media == 0xf8 && FAT_FIRST_ENT(sb, 0xff) == first) { + /* bad, reported on Nokia phone with USB storage */ } else if (media == 0xf0 && FAT_FIRST_ENT(sb, 0xf8) == first) { /* bad, reported with a MO disk on win95/me */ } else if (first == 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/proc/array.c linux-2.6.9/fs/proc/array.c --- linux.vanilla-2.6.9/fs/proc/array.c 2004-10-20 23:17:19.000000000 +0100 +++ linux-2.6.9/fs/proc/array.c 2004-11-25 20:22:10.000000000 +0000 @@ -171,7 +171,7 @@ get_task_state(p), (p->sleep_avg/1024)*100/(1020000000/1024), p->tgid, - p->pid, p->pid ? p->real_parent->pid : 0, + p->pid, p->pid ? p->group_leader->real_parent->tgid : 0, p->pid && p->ptrace ? p->parent->pid : 0, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); @@ -356,7 +356,7 @@ nice = task_nice(task); read_lock(&tasklist_lock); - ppid = task->pid ? task->real_parent->pid : 0; + ppid = task->pid ? task->group_leader->real_parent->tgid : 0; read_unlock(&tasklist_lock); /* Temporary variable needed for gcc-2.96 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/proc/base.c linux-2.6.9/fs/proc/base.c --- linux.vanilla-2.6.9/fs/proc/base.c 2004-10-20 23:17:19.000000000 +0100 +++ linux-2.6.9/fs/proc/base.c 2004-11-25 21:21:16.000000000 +0000 @@ -307,7 +307,7 @@ (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto out; rmb(); - if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) + if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE)) goto out; if (security_ptrace(current, task)) goto out; @@ -342,7 +342,7 @@ if (!mm) goto out; if (!mm->arg_end) - goto out; /* Shh! No looking before we're done */ + goto out_mm; /* Shh! No looking before we're done */ len = mm->arg_end - mm->arg_start; @@ -365,8 +365,8 @@ res = strnlen(buffer, res); } } +out_mm: mmput(mm); - out: return res; } @@ -929,7 +929,9 @@ if (mm) dumpable = mm->dumpable; task_unlock(task); - return dumpable; + if(dumpable == 1) + return 1; + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/proc/task_mmu.c linux-2.6.9/fs/proc/task_mmu.c --- linux.vanilla-2.6.9/fs/proc/task_mmu.c 2004-10-20 23:17:19.000000000 +0100 +++ linux-2.6.9/fs/proc/task_mmu.c 2004-11-25 21:35:42.000000000 +0000 @@ -35,9 +35,9 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, int *data, int *resident) { - *shared = mm->shared_vm; + *shared = mm->rss - mm->anon_rss; *text = (mm->end_code - mm->start_code) >> PAGE_SHIFT; - *data = mm->total_vm - mm->shared_vm - *text; + *data = mm->total_vm - mm->shared_vm; *resident = mm->rss; return mm->total_vm; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/smbfs/proc.c linux-2.6.9/fs/smbfs/proc.c --- linux.vanilla-2.6.9/fs/smbfs/proc.c 2004-10-20 23:17:20.000000000 +0100 +++ linux-2.6.9/fs/smbfs/proc.c 2004-11-25 20:32:26.000000000 +0000 @@ -1427,9 +1427,9 @@ * So we must first calculate the amount of padding used by the server. */ data_off -= hdrlen; - if (data_off > SMB_READX_MAX_PAD) { - PARANOIA("offset is larger than max pad!\n"); - PARANOIA("%d > %d\n", data_off, SMB_READX_MAX_PAD); + if (data_off > SMB_READX_MAX_PAD || data_off < 0) { + PARANOIA("offset is larger than SMB_READX_MAX_PAD or negative!\n"); + PARANOIA("%d > %d || %d < 0\n", data_off, SMB_READX_MAX_PAD, data_off); req->rq_rlen = req->rq_bufsize + 1; return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/fs/smbfs/request.c linux-2.6.9/fs/smbfs/request.c --- linux.vanilla-2.6.9/fs/smbfs/request.c 2004-10-20 22:33:50.000000000 +0100 +++ linux-2.6.9/fs/smbfs/request.c 2004-11-25 20:32:26.000000000 +0000 @@ -588,8 +588,18 @@ data_count = WVAL(inbuf, smb_drcnt); /* Modify offset for the split header/buffer we use */ - data_offset -= hdrlen; - parm_offset -= hdrlen; + if (data_count || data_offset) { + if (unlikely(data_offset < hdrlen)) + goto out_bad_data; + else + data_offset -= hdrlen; + } + if (parm_count || parm_offset) { + if (unlikely(parm_offset < hdrlen)) + goto out_bad_parm; + else + parm_offset -= hdrlen; + } if (parm_count == parm_tot && data_count == data_tot) { /* @@ -600,18 +610,22 @@ * response that fits. */ VERBOSE("single trans2 response " - "dcnt=%d, pcnt=%d, doff=%d, poff=%d\n", + "dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", data_count, parm_count, data_offset, parm_offset); req->rq_ldata = data_count; req->rq_lparm = parm_count; req->rq_data = req->rq_buffer + data_offset; req->rq_parm = req->rq_buffer + parm_offset; + if (unlikely(parm_offset + parm_count > req->rq_rlen)) + goto out_bad_parm; + if (unlikely(data_offset + data_count > req->rq_rlen)) + goto out_bad_data; return 0; } VERBOSE("multi trans2 response " - "frag=%d, dcnt=%d, pcnt=%d, doff=%d, poff=%d\n", + "frag=%d, dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", req->rq_fragment, data_count, parm_count, data_offset, parm_offset); @@ -634,16 +648,20 @@ req->rq_trans2buffer = smb_kmalloc(buf_len, GFP_NOFS); if (!req->rq_trans2buffer) goto out_no_mem; + memset(req->rq_trans2buffer, 0, buf_len); req->rq_parm = req->rq_trans2buffer; req->rq_data = req->rq_trans2buffer + parm_tot; - } else if (req->rq_total_data < data_tot || - req->rq_total_parm < parm_tot) + } else if (unlikely(req->rq_total_data < data_tot || + req->rq_total_parm < parm_tot)) goto out_data_grew; - if (parm_disp + parm_count > req->rq_total_parm) + if (unlikely(parm_disp + parm_count > req->rq_total_parm || + parm_offset + parm_count > req->rq_rlen)) goto out_bad_parm; - if (data_disp + data_count > req->rq_total_data) + + if (unlikely(data_disp + data_count > req->rq_total_data || + data_offset + data_count > req->rq_rlen)) goto out_bad_data; inbuf = req->rq_buffer; @@ -657,15 +675,17 @@ * Check whether we've received all of the data. Note that * we use the packet totals -- total lengths might shrink! */ - if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) + if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) { + req->rq_ldata = data_tot; + req->rq_lparm = parm_tot; return 0; + } return 1; out_too_long: - printk(KERN_ERR "smb_trans2: data/param too long, data=%d, parm=%d\n", + printk(KERN_ERR "smb_trans2: data/param too long, data=%u, parm=%u\n", data_tot, parm_tot); - req->rq_errno = -EIO; - goto out; + goto out_EIO; out_no_mem: printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n", req->rq_trans2bufsize); @@ -673,16 +693,15 @@ goto out; out_data_grew: printk(KERN_ERR "smb_trans2: data/params grew!\n"); - req->rq_errno = -EIO; - goto out; + goto out_EIO; out_bad_parm: - printk(KERN_ERR "smb_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n", - parm_disp, parm_count, parm_tot); - req->rq_errno = -EIO; - goto out; + printk(KERN_ERR "smb_trans2: invalid parms, disp=%u, cnt=%u, tot=%u, ofs=%u\n", + parm_disp, parm_count, parm_tot, parm_offset); + goto out_EIO; out_bad_data: - printk(KERN_ERR "smb_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n", - data_disp, data_count, data_tot); + printk(KERN_ERR "smb_trans2: invalid data, disp=%u, cnt=%u, tot=%u, ofs=%u\n", + data_disp, data_count, data_tot, data_offset); +out_EIO: req->rq_errno = -EIO; out: return req->rq_errno; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-arm/atomic.h linux-2.6.9/include/asm-arm/atomic.h --- linux.vanilla-2.6.9/include/asm-arm/atomic.h 2004-10-20 23:17:20.000000000 +0100 +++ linux-2.6.9/include/asm-arm/atomic.h 2004-11-15 16:58:36.000000000 +0000 @@ -149,6 +149,8 @@ #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) +#define atomic_inc_return(v) (atomic_add_return(1, v)) +#define atomic_dec_return(v) (atomic_sub_return(1, v)) #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-arm26/atomic.h linux-2.6.9/include/asm-arm26/atomic.h --- linux.vanilla-2.6.9/include/asm-arm26/atomic.h 2004-10-20 22:32:12.000000000 +0100 +++ linux-2.6.9/include/asm-arm26/atomic.h 2004-11-15 16:58:46.000000000 +0000 @@ -105,6 +105,27 @@ local_irq_restore(flags); } +static inline int atomic_add_return(int i, volatile atomic_t *v) +{ + unsigned long flags; + int val; + + local_irq_save(flags); + val = v->counter + i; + v->counter = val; + local_irq_restore(flags); + + return val; +} + +static inline int atomic_sub_return(int i, volatile atomic_t *v) +{ + return atomic_add_return(-i, v); +} + +#define atomic_inc_return(v) (atomic_add_return(1,v)) +#define atomic_dec_return(v) (atomic_sub_return(1,v)) + /* Atomic operations are already serializing on ARM */ #define smp_mb__before_atomic_dec() barrier() #define smp_mb__after_atomic_dec() barrier() diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-i386/atomic.h linux-2.6.9/include/asm-i386/atomic.h --- linux.vanilla-2.6.9/include/asm-i386/atomic.h 2004-10-20 22:32:00.000000000 +0100 +++ linux-2.6.9/include/asm-i386/atomic.h 2004-11-15 16:54:08.000000000 +0000 @@ -2,6 +2,8 @@ #define __ARCH_I386_ATOMIC__ #include +#include +#include /* * Atomic operations that C can't guarantee us. Useful for @@ -176,6 +178,46 @@ return c; } +/** + * atomic_add_return - add and return + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns @i + @v + */ +static __inline__ int atomic_add_return(int i, atomic_t *v) +{ + int __i; +#ifdef CONFIG_M386 + if(unlikely(boot_cpu_data.x86==3)) + goto no_xadd; +#endif + /* Modern 486+ processor */ + __i = i; + __asm__ __volatile__( + LOCK "xaddl %0, %1;" + :"=r"(i) + :"m"(v->counter), "0"(i)); + return i + __i; + +#ifdef CONFIG_M386 +no_xadd: /* Legacy 386 processor */ + local_irq_disable(); + __i = atomic_read(v); + atomic_set(v, i + __i); + local_irq_enable(); + return i + __i; +#endif +} + +static __inline__ int atomic_sub_return(int i, atomic_t *v) +{ + return atomic_add_return(-i,v); +} + +#define atomic_inc_return(v) (atomic_add_return(1,v)) +#define atomic_dec_return(v) (atomic_sub_return(1,v)) + /* These are x86-specific, used by some header files */ #define atomic_clear_mask(mask, addr) \ __asm__ __volatile__(LOCK "andl %0,%1" \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-i386/param.h linux-2.6.9/include/asm-i386/param.h --- linux.vanilla-2.6.9/include/asm-i386/param.h 2004-10-20 22:32:01.000000000 +0100 +++ linux-2.6.9/include/asm-i386/param.h 2004-11-25 23:06:10.000000000 +0000 @@ -1,8 +1,10 @@ #ifndef _ASMi386_PARAM_H #define _ASMi386_PARAM_H +#include + #ifdef __KERNEL__ -# define HZ 1000 /* Internal kernel timer frequency */ +# define HZ (CONFIG_X86_HZ) # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-i386/setup.h linux-2.6.9/include/asm-i386/setup.h --- linux.vanilla-2.6.9/include/asm-i386/setup.h 2004-10-20 22:32:01.000000000 +0100 +++ linux-2.6.9/include/asm-i386/setup.h 2004-10-28 00:45:37.000000000 +0100 @@ -55,7 +55,7 @@ #define KERNEL_START (*(unsigned long *) (PARAM+0x214)) #define INITRD_START (*(unsigned long *) (PARAM+0x218)) #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) -#define EDID_INFO (*(struct edid_info *) (PARAM+0x440)) +#define EDID_INFO (*(struct edid_info *) (PARAM+0x140)) #define EDD_NR (*(unsigned char *) (PARAM+EDDNR)) #define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF)) #define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-sparc64/atomic.h linux-2.6.9/include/asm-sparc64/atomic.h --- linux.vanilla-2.6.9/include/asm-sparc64/atomic.h 2004-10-20 22:32:14.000000000 +0100 +++ linux-2.6.9/include/asm-sparc64/atomic.h 2004-11-15 16:58:55.000000000 +0000 @@ -40,6 +40,12 @@ #define atomic_inc_return(v) __atomic_add(1, v) #define atomic64_inc_return(v) __atomic64_add(1, v) +#define atomic_sub_return(i, v) __atomic_sub(i, v) +#define atomic64_sub_return(i, v) __atomic64_sub(i, v) + +#define atomic_add_return(i, v) __atomic_add(i, v) +#define atomic64_add_return(i, v) __atomic64_add(i, v) + /* * atomic_inc_and_test - increment and test * @v: pointer of type atomic_t diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-x86_64/acpi.h linux-2.6.9/include/asm-x86_64/acpi.h --- linux.vanilla-2.6.9/include/asm-x86_64/acpi.h 2004-10-20 23:17:21.000000000 +0100 +++ linux-2.6.9/include/asm-x86_64/acpi.h 2004-11-15 23:25:16.000000000 +0000 @@ -166,6 +166,8 @@ extern u8 x86_acpiid_to_apicid[]; +extern int acpi_skip_timer_override; + #endif /*__KERNEL__*/ #endif /*_ASM_ACPI_H*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-x86_64/atomic.h linux-2.6.9/include/asm-x86_64/atomic.h --- linux.vanilla-2.6.9/include/asm-x86_64/atomic.h 2004-10-20 23:17:21.000000000 +0100 +++ linux-2.6.9/include/asm-x86_64/atomic.h 2004-11-15 16:58:23.000000000 +0000 @@ -338,6 +338,31 @@ return c; } +/** + * atomic_add_return - add and return + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns @i + @v + */ +static __inline__ int atomic_add_return(int i, atomic_t *v) +{ + int __i = i; + __asm__ __volatile__( + LOCK "xaddl %0, %1;" + :"=r"(i) + :"m"(v->counter), "0"(i)); + return i + __i; +} + +static __inline__ int atomic_sub_return(int i, atomic_t *v) +{ + return atomic_add_return(-i,v); +} + +#define atomic_inc_return(v) (atomic_add_return(1,v)) +#define atomic_dec_return(v) (atomic_sub_return(1,v)) + /* These are x86-specific, used by some header files */ #define atomic_clear_mask(mask, addr) \ __asm__ __volatile__(LOCK "andl %0,%1" \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-x86_64/bootsetup.h linux-2.6.9/include/asm-x86_64/bootsetup.h --- linux.vanilla-2.6.9/include/asm-x86_64/bootsetup.h 2004-10-20 22:32:09.000000000 +0100 +++ linux-2.6.9/include/asm-x86_64/bootsetup.h 2004-11-02 19:47:47.000000000 +0000 @@ -25,7 +25,7 @@ #define KERNEL_START (*(unsigned int *) (PARAM+0x214)) #define INITRD_START (*(unsigned int *) (PARAM+0x218)) #define INITRD_SIZE (*(unsigned int *) (PARAM+0x21c)) -#define EDID_INFO (*(struct edid_info *) (PARAM+0x440)) +#define EDID_INFO (*(struct edid_info *) (PARAM+0x140)) #define EDD_NR (*(unsigned char *) (PARAM+EDDNR)) #define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF)) #define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/asm-x86_64/hw_irq.h linux-2.6.9/include/asm-x86_64/hw_irq.h --- linux.vanilla-2.6.9/include/asm-x86_64/hw_irq.h 2004-10-20 23:17:21.000000000 +0100 +++ linux-2.6.9/include/asm-x86_64/hw_irq.h 2004-12-01 21:05:19.000000000 +0000 @@ -130,7 +130,7 @@ "push $" #nr "-256 ; " \ "jmp common_interrupt"); -#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) +#if defined(CONFIG_X86_IO_APIC) static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { if (IO_APIC_IRQ(i)) send_IPI_self(IO_APIC_VECTOR(i)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/binfmts.h linux-2.6.9/include/linux/binfmts.h --- linux.vanilla-2.6.9/include/linux/binfmts.h 2004-10-20 22:32:05.000000000 +0100 +++ linux-2.6.9/include/linux/binfmts.h 2004-11-15 23:25:16.000000000 +0000 @@ -69,6 +69,11 @@ extern int search_binary_handler(struct linux_binprm *,struct pt_regs *); extern int flush_old_exec(struct linux_binprm * bprm); +extern int suid_dumpable; +#define SUID_DUMP_DISABLE 0 /* No setuid dumping */ +#define SUID_DUMP_USER 1 /* Dump as user of process */ +#define SUID_DUMP_ROOT 2 /* Dump as root */ + /* Stack area protections */ #define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */ #define EXSTACK_DISABLE_X 1 /* Disable executable stacks */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/cdrom.h linux-2.6.9/include/linux/cdrom.h --- linux.vanilla-2.6.9/include/linux/cdrom.h 2004-10-20 23:17:22.000000000 +0100 +++ linux-2.6.9/include/linux/cdrom.h 2004-11-15 23:25:16.000000000 +0000 @@ -452,6 +452,7 @@ #define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e #define GPCMD_READ_10 0x28 #define GPCMD_READ_12 0xa8 +#define GPCMD_READ_BUFFER_CAPACITY 0x5c #define GPCMD_READ_CDVD_CAPACITY 0x25 #define GPCMD_READ_CD 0xbe #define GPCMD_READ_CD_MSF 0xb9 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/compiler.h linux-2.6.9/include/linux/compiler.h --- linux.vanilla-2.6.9/include/linux/compiler.h 2004-10-20 23:17:22.000000000 +0100 +++ linux-2.6.9/include/linux/compiler.h 2004-11-15 23:25:16.000000000 +0000 @@ -1,6 +1,8 @@ #ifndef __LINUX_COMPILER_H #define __LINUX_COMPILER_H +#ifndef __ASSEMBLY__ + #ifdef __CHECKER__ # define __user __attribute__((noderef, address_space(1))) # define __kernel /* default address space */ @@ -21,7 +23,6 @@ #ifdef __KERNEL__ -#ifndef __ASSEMBLY__ #if __GNUC__ > 3 # include /* catch-all for GCC 4, 5, etc. */ #elif __GNUC__ == 3 @@ -31,7 +32,6 @@ #else # error Sorry, your compiler is too old/not recognized. #endif -#endif /* Intel compiler defines __GNUC__. So we will overwrite implementations * coming from above header files here @@ -61,6 +61,8 @@ (typeof(ptr)) (__ptr + (off)); }) #endif +#endif /* __ASSEMBLY__ */ + #endif /* __KERNEL__ */ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/edd.h linux-2.6.9/include/linux/edd.h --- linux.vanilla-2.6.9/include/linux/edd.h 2004-10-20 22:32:08.000000000 +0100 +++ linux-2.6.9/include/linux/edd.h 2004-11-25 20:20:16.000000000 +0000 @@ -49,6 +49,10 @@ #define EDD_MBR_SIG_MAX 16 /* max number of signatures to store */ #define EDD_MBR_SIG_NR_BUF 0x1ea /* addr of number of MBR signtaures at EDD_MBR_SIG_BUF in boot_params - treat this as 1 byte */ +#define EDD_CL_EQUALS 0x3d646465 /* "edd=" */ +#define EDD_CL_OFF 0x666f /* "of" for off */ +#define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */ + #ifndef __ASSEMBLY__ #define EDD_EXT_FIXED_DISK_ACCESS (1 << 0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/ide.h linux-2.6.9/include/linux/ide.h --- linux.vanilla-2.6.9/include/linux/ide.h 2004-10-20 23:17:22.000000000 +0100 +++ linux-2.6.9/include/linux/ide.h 2004-12-02 17:18:43.000000000 +0000 @@ -266,6 +266,7 @@ * Register new hardware with ide */ int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp); +int ide_register_hw_with_fixup(hw_regs_t *hw, struct hwif_s **hwifp, void (*fixup)(struct hwif_s *)); /* * Set up hw_regs_t structure before calling ide_register_hw (optional) @@ -780,6 +781,7 @@ unsigned int max_failures; /* maximum allowed failure count */ u64 capacity64; /* total number of sectors */ + u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */ int lun; /* logical unit */ int crc_count; /* crc counter to reduce drive speed */ @@ -815,6 +817,7 @@ #define IDE_CHIPSET_IS_PCI(c) ((IDE_CHIPSET_PCI_MASK >> (c)) & 1) struct ide_pci_device_s; +struct ide_task_s; typedef struct hwif_s { struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ @@ -822,6 +825,7 @@ struct hwgroup_s *hwgroup; /* actually (ide_hwgroup_t *) */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ + u16 key; /* /proc persistent keying */ char name[6]; /* name of interface, eg. "ide0" */ /* task file registers for pata and sata */ @@ -879,6 +883,10 @@ // u8 (*ratemask)(ide_drive_t *); // /* device rate limiter */ // u8 (*ratefilter)(ide_drive_t *, u8); + /* hwif remove hook, called on unload/pci remove paths*/ + void (*remove)(struct hwif_s *); + /* allow command filter/control */ + int (*raw_taskfile)(ide_drive_t *, struct ide_task_s *, u8 *); #endif void (*ata_input_data)(ide_drive_t *, void *, u32); @@ -945,7 +953,9 @@ unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ + unsigned configured : 1; /* this hwif exists and is set up (may not be "present") */ unsigned hold : 1; /* this interface is always present */ + unsigned user_dev : 1; /* user ioctl created device */ unsigned serialized : 1; /* serialized all channel operation */ unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ unsigned reset : 1; /* reset after probe */ @@ -955,6 +965,7 @@ unsigned no_lba48_dma : 1; /* 1 = cannot do LBA48 DMA */ unsigned no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */ unsigned auto_poll : 1; /* supports nop auto-poll */ + unsigned polling : 1; /* doing a polled command ignore irqs */ struct device gendev; struct semaphore gendev_rel_sem; /* To deal with device release() */ @@ -1047,6 +1058,11 @@ extern int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val); extern void ide_add_generic_settings(ide_drive_t *drive); +extern void *ide_drive_to_key(ide_drive_t *drive); +extern ide_drive_t *ide_drive_from_key(void *); +extern void *ide_hwif_to_key(ide_hwif_t *hwif); +extern ide_hwif_t *ide_hwif_from_key(void *); + /* * /proc/ide interface */ @@ -1063,6 +1079,7 @@ extern void proc_ide_create(void); extern void proc_ide_destroy(void); extern void destroy_proc_ide_drives(ide_hwif_t *); +extern void destroy_proc_ide_interface(ide_hwif_t *); extern void create_proc_ide_interfaces(void); extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *); extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *); @@ -1175,6 +1192,7 @@ extern int noautodma; extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs); +extern int ide_end_dequeued_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs); /* * This is used on exit from the driver to designate the next irq handler @@ -1419,6 +1437,7 @@ extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); extern ide_startstop_t task_out_intr(ide_drive_t *); +extern int ide_diag_taskfile(ide_drive_t *, ide_task_t *, unsigned long, u8 *); extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *); int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long); @@ -1470,9 +1489,11 @@ extern void ide_pci_unregister_driver(struct pci_driver *driver); extern void ide_pci_setup_ports(struct pci_dev *dev, struct ide_pci_device_s *d, int autodma, int pciirq, ata_index_t *index); extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d); +extern void ide_pci_remove_hwifs(struct pci_dev *dev); extern void default_hwif_iops(ide_hwif_t *); extern void default_hwif_mmiops(ide_hwif_t *); +extern void removed_hwif_iops(ide_hwif_t *); extern void default_hwif_transport(ide_hwif_t *); int ide_register_driver(ide_driver_t *driver); @@ -1516,6 +1537,7 @@ void (*init_iops)(ide_hwif_t *); void (*init_hwif)(ide_hwif_t *); void (*init_dma)(ide_hwif_t *, unsigned long); + void (*fixup)(ide_hwif_t *); u8 channels; u8 autodma; ide_pci_enablebit_t enablebits[2]; @@ -1570,10 +1592,14 @@ #endif extern int ide_hwif_request_regions(ide_hwif_t *hwif); -extern void ide_hwif_release_regions(ide_hwif_t* hwif); -extern void ide_unregister (unsigned int index); +extern void ide_hwif_release_regions(ide_hwif_t *hwif); +extern int ide_unregister_hwif(ide_hwif_t *hwif); +extern int __ide_unregister_hwif(ide_hwif_t *hwif); + +extern void ide_undecoded_slave(ide_hwif_t *hwif); -extern int probe_hwif_init(ide_hwif_t *); +extern int probe_hwif_init(ide_hwif_t *hwif); +extern int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)); static inline void *ide_get_hwifdata (ide_hwif_t * hwif) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/kernel.h linux-2.6.9/include/linux/kernel.h --- linux.vanilla-2.6.9/include/linux/kernel.h 2004-10-20 23:17:22.000000000 +0100 +++ linux-2.6.9/include/linux/kernel.h 2004-10-28 00:44:45.000000000 +0100 @@ -66,6 +66,7 @@ }) extern struct notifier_block *panic_notifier_list; +extern long (*panic_blink)(long time); NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))); asmlinkage NORET_TYPE void do_exit(long error_code) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/mm.h linux-2.6.9/include/linux/mm.h --- linux.vanilla-2.6.9/include/linux/mm.h 2004-10-20 23:17:23.000000000 +0100 +++ linux-2.6.9/include/linux/mm.h 2004-12-01 21:08:51.000000000 +0000 @@ -673,7 +673,7 @@ extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *); extern int split_vma(struct mm_struct *, struct vm_area_struct *, unsigned long addr, int new_below); -extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); +extern int insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *, struct rb_node **, struct rb_node *); extern struct vm_area_struct *copy_vma(struct vm_area_struct **, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/pci_ids.h linux-2.6.9/include/linux/pci_ids.h --- linux.vanilla-2.6.9/include/linux/pci_ids.h 2004-10-20 23:17:25.000000000 +0100 +++ linux-2.6.9/include/linux/pci_ids.h 2004-11-25 22:32:34.000000000 +0000 @@ -344,6 +344,7 @@ #define PCI_DEVICE_ID_ATI_RS300_200 0x5833 /* ATI IXP Chipset */ #define PCI_DEVICE_ID_ATI_IXP_IDE 0x4349 +#define PCI_DEVICE_ID_ATI_IXP2_IDE 0x4369 /* True name not yet sure */ #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 @@ -1022,10 +1023,14 @@ #define PCI_DEVICE_ID_AL_M1647 0x1647 #define PCI_DEVICE_ID_AL_M1651 0x1651 #define PCI_DEVICE_ID_AL_M1671 0x1671 +#define PCI_DEVICE_ID_AL_M1681 0x1681 +#define PCI_DEVICE_ID_AL_M1683 0x1683 +#define PCI_DEVICE_ID_AL_M1689 0x1689 #define PCI_DEVICE_ID_AL_M1543 0x1543 #define PCI_DEVICE_ID_AL_M3307 0x3307 #define PCI_DEVICE_ID_AL_M4803 0x5215 #define PCI_DEVICE_ID_AL_M5219 0x5219 +#define PCI_DEVICE_ID_AL_M5228 0x5228 #define PCI_DEVICE_ID_AL_M5229 0x5229 #define PCI_DEVICE_ID_AL_M5237 0x5237 #define PCI_DEVICE_ID_AL_M5243 0x5243 @@ -1199,6 +1204,7 @@ #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_PT880 0x0258 #define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259 #define PCI_DEVICE_ID_VIA_3269_0 0x0269 #define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282 @@ -1257,7 +1263,6 @@ #define PCI_DEVICE_ID_VIA_8377_0 0x3189 #define PCI_DEVICE_ID_VIA_8378_0 0x3205 #define PCI_DEVICE_ID_VIA_8783_0 0x3208 -#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 @@ -1648,6 +1653,7 @@ #define PCI_VENDOR_ID_ITE 0x1283 #define PCI_DEVICE_ID_ITE_IT8172G 0x8172 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801 +#define PCI_DEVICE_ID_ITE_8212 0x8212 #define PCI_DEVICE_ID_ITE_8872 0x8872 #define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 @@ -2330,3 +2336,6 @@ #define PCI_DEVICE_ID_ARK_STING 0xa091 #define PCI_DEVICE_ID_ARK_STINGARK 0xa099 #define PCI_DEVICE_ID_ARK_2000MT 0xa0a1 + +#define PCI_VENDOR_ID_WORKBIT 0x1145 +#define PCI_DEVICE_ID_WORKBIT_CB 0xf021 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/raid/linear.h linux-2.6.9/include/linux/raid/linear.h --- linux.vanilla-2.6.9/include/linux/raid/linear.h 2004-10-20 22:32:06.000000000 +0100 +++ linux-2.6.9/include/linux/raid/linear.h 2004-11-15 16:04:37.000000000 +0000 @@ -5,8 +5,8 @@ struct dev_info { mdk_rdev_t *rdev; - unsigned long size; - unsigned long offset; + sector_t size; + sector_t offset; }; typedef struct dev_info dev_info_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/sched.h linux-2.6.9/include/linux/sched.h --- linux.vanilla-2.6.9/include/linux/sched.h 2004-10-20 23:17:25.000000000 +0100 +++ linux-2.6.9/include/linux/sched.h 2004-11-25 21:35:42.000000000 +0000 @@ -225,12 +225,12 @@ unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack; unsigned long arg_start, arg_end, env_start, env_end; - unsigned long rss, total_vm, locked_vm, shared_vm; + unsigned long rss, anon_rss, total_vm, locked_vm, shared_vm; unsigned long exec_vm, stack_vm, reserved_vm, def_flags; unsigned long saved_auxv[42]; /* for /proc/PID/auxv */ - unsigned dumpable:1; + unsigned dumpable:2; cpumask_t cpu_vm_mask; /* Architecture-specific MM context */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/slab.h linux-2.6.9/include/linux/slab.h --- linux.vanilla-2.6.9/include/linux/slab.h 2004-10-20 23:17:25.000000000 +0100 +++ linux-2.6.9/include/linux/slab.h 2004-11-17 19:28:50.000000000 +0000 @@ -13,6 +13,7 @@ #include /* kmalloc_sizes.h needs CONFIG_ options */ #include +#include #include #include /* kmalloc_sizes.h needs PAGE_SIZE */ #include /* kmalloc_sizes.h needs L1_CACHE_BYTES */ @@ -53,7 +54,7 @@ #define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */ /* prototypes */ -extern void kmem_cache_init(void); +extern void __init kmem_cache_init(void); extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, void (*)(void *, kmem_cache_t *, unsigned long), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/socket.h linux-2.6.9/include/linux/socket.h --- linux.vanilla-2.6.9/include/linux/socket.h 2004-10-20 23:17:25.000000000 +0100 +++ linux-2.6.9/include/linux/socket.h 2004-12-10 20:36:00.000000000 +0000 @@ -90,6 +90,10 @@ (struct cmsghdr *)(ctl) : \ (struct cmsghdr *)NULL) #define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) +#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \ + (cmsg)->cmsg_len <= (unsigned long) \ + ((mhdr)->msg_controllen - \ + ((char *)(cmsg) - (char *)(mhdr)->msg_control))) /* * This mess will go away with glibc diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/sysctl.h linux-2.6.9/include/linux/sysctl.h --- linux.vanilla-2.6.9/include/linux/sysctl.h 2004-10-20 23:17:25.000000000 +0100 +++ linux-2.6.9/include/linux/sysctl.h 2004-10-16 22:44:36.000000000 +0100 @@ -134,6 +134,7 @@ KERN_SPARC_SCONS_PWROFF=64, /* int: serial console power-off halt */ KERN_HZ_TIMER=65, /* int: hz timer on or off */ KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */ + KERN_SETUID_DUMPABLE=67, /* int: behaviour of dumps for setuid core */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/linux/writeback.h linux-2.6.9/include/linux/writeback.h --- linux.vanilla-2.6.9/include/linux/writeback.h 2004-10-20 23:17:25.000000000 +0100 +++ linux-2.6.9/include/linux/writeback.h 2004-12-10 20:47:01.000000000 +0000 @@ -86,6 +86,7 @@ int wakeup_bdflush(long nr_pages); void laptop_io_completion(void); void laptop_sync_completion(void); +void throttle_vm_writeout(void); /* These are exported to sysctl. */ extern int dirty_background_ratio; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/net/neighbour.h linux-2.6.9/include/net/neighbour.h --- linux.vanilla-2.6.9/include/net/neighbour.h 2004-10-20 23:17:27.000000000 +0100 +++ linux-2.6.9/include/net/neighbour.h 2004-11-15 16:09:17.000000000 +0000 @@ -185,7 +185,7 @@ struct timer_list gc_timer; struct timer_list proxy_timer; struct sk_buff_head proxy_queue; - int entries; + atomic_t entries; rwlock_t lock; unsigned long last_rand; struct neigh_parms *parms_list; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/include/net/xfrm.h linux-2.6.9/include/net/xfrm.h --- linux.vanilla-2.6.9/include/net/xfrm.h 2004-10-20 23:17:27.000000000 +0100 +++ linux-2.6.9/include/net/xfrm.h 2004-12-10 20:42:09.000000000 +0000 @@ -601,7 +601,7 @@ if (sk && sk->sk_policy[XFRM_POLICY_IN]) return __xfrm_policy_check(sk, dir, skb, family); - return !xfrm_policy_list[dir] || + return (!xfrm_policy_list[dir] && !skb->sp) || (skb->dst->flags & DST_NOPOLICY) || __xfrm_policy_check(sk, dir, skb, family); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/kernel/fork.c linux-2.6.9/kernel/fork.c --- linux.vanilla-2.6.9/kernel/fork.c 2004-10-20 23:17:28.000000000 +0100 +++ linux-2.6.9/kernel/fork.c 2004-11-25 21:35:42.000000000 +0000 @@ -297,6 +297,7 @@ mm->free_area_cache = oldmm->mmap_base; mm->map_count = 0; mm->rss = 0; + mm->anon_rss = 0; cpus_clear(mm->cpu_vm_mask); mm->mm_rb = RB_ROOT; rb_link = &mm->mm_rb.rb_node; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/kernel/futex.c linux-2.6.9/kernel/futex.c --- linux.vanilla-2.6.9/kernel/futex.c 2004-10-20 22:32:19.000000000 +0100 +++ linux-2.6.9/kernel/futex.c 2004-12-01 21:03:28.000000000 +0000 @@ -538,8 +538,8 @@ return 0; if (time == 0) return -ETIMEDOUT; - /* A spurious wakeup should never happen. */ - WARN_ON(!signal_pending(current)); + /* We expect signal_pending(current), but another thread may + * have handled it for us already. */ return -EINTR; out_unqueue: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/kernel/panic.c linux-2.6.9/kernel/panic.c --- linux.vanilla-2.6.9/kernel/panic.c 2004-10-20 23:17:29.000000000 +0100 +++ linux-2.6.9/kernel/panic.c 2004-10-28 00:44:45.000000000 +0100 @@ -37,6 +37,15 @@ } __setup("panic=", panic_setup); +static long no_blink(long time) +{ + return 0; +} + +/* Returns how long it waited in ms */ +long (*panic_blink)(long time) = no_blink; +EXPORT_SYMBOL(panic_blink); + /** * panic - halt the system * @fmt: The text string to print @@ -49,6 +58,7 @@ NORET_TYPE void panic(const char * fmt, ...) { + long i; static char buf[1024]; va_list args; #if defined(CONFIG_ARCH_S390) @@ -70,15 +80,16 @@ if (panic_timeout > 0) { - int i; /* * Delay timeout seconds before rebooting the machine. * We can't use the "normal" timers since we just panicked.. */ printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout); - for (i = 0; i < panic_timeout; i++) { + for (i = 0; i < panic_timeout*1000; ) { touch_nmi_watchdog(); - mdelay(1000); + i += panic_blink(i); + mdelay(1); + i++; } /* * Should we run the reboot notifier. For the moment Im @@ -99,8 +110,11 @@ disabled_wait(caller); #endif local_irq_enable(); - for (;;) - ; + for (i = 0;;) { + i += panic_blink(i); + mdelay(1); + i++; + } } EXPORT_SYMBOL(panic); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/kernel/sys.c linux-2.6.9/kernel/sys.c --- linux.vanilla-2.6.9/kernel/sys.c 2004-10-20 23:17:29.000000000 +0100 +++ linux-2.6.9/kernel/sys.c 2004-10-16 22:13:51.000000000 +0100 @@ -591,7 +591,7 @@ } if (new_egid != old_egid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } if (rgid != (gid_t) -1 || @@ -621,7 +621,7 @@ { if(old_egid != gid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->gid = current->egid = current->sgid = current->fsgid = gid; @@ -630,7 +630,7 @@ { if(old_egid != gid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->egid = current->fsgid = gid; @@ -659,7 +659,7 @@ if(dumpclear) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->uid = new_ruid; @@ -716,7 +716,7 @@ if (new_euid != old_euid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = current->euid = new_euid; @@ -764,7 +764,7 @@ if (old_euid != uid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = current->euid = uid; @@ -807,7 +807,7 @@ if (euid != (uid_t) -1) { if (euid != current->euid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->euid = euid; @@ -855,7 +855,7 @@ if (egid != (gid_t) -1) { if (egid != current->egid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->egid = egid; @@ -900,7 +900,7 @@ { if (uid != old_fsuid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = uid; @@ -928,7 +928,7 @@ { if (gid != old_fsgid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsgid = gid; @@ -1683,7 +1683,7 @@ error = 1; break; case PR_SET_DUMPABLE: - if (arg2 != 0 && arg2 != 1) { + if (arg2 < 0 || arg2 > 2) { error = -EINVAL; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/kernel/sysctl.c linux-2.6.9/kernel/sysctl.c --- linux.vanilla-2.6.9/kernel/sysctl.c 2004-10-20 23:17:29.000000000 +0100 +++ linux-2.6.9/kernel/sysctl.c 2004-10-16 22:13:51.000000000 +0100 @@ -58,6 +58,7 @@ extern int max_threads; extern int sysrq_enabled; extern int core_uses_pid; +extern int suid_dumpable; extern char core_pattern[]; extern int cad_pid; extern int pid_max; @@ -619,6 +620,14 @@ .proc_handler = &proc_unknown_nmi_panic, }, #endif + { + .ctl_name = KERN_SETUID_DUMPABLE, + .procname = "suid_dumpable", + .data = &suid_dumpable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = 0 } }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/kernel/timer.c linux-2.6.9/kernel/timer.c --- linux.vanilla-2.6.9/kernel/timer.c 2004-10-20 23:17:29.000000000 +0100 +++ linux-2.6.9/kernel/timer.c 2004-11-25 21:21:59.000000000 +0000 @@ -308,6 +308,8 @@ goto repeat; } list_del(&timer->entry); + /* Need to make sure that anybody who sees a NULL base also sees the list ops */ + smp_wmb(); timer->base = NULL; spin_unlock_irqrestore(&base->lock, flags); @@ -789,13 +791,12 @@ do { ticks--; update_wall_time_one_tick(); + if (xtime.tv_nsec >= 1000000000) { + xtime.tv_nsec -= 1000000000; + xtime.tv_sec++; + second_overflow(); + } } while (ticks); - - if (xtime.tv_nsec >= 1000000000) { - xtime.tv_nsec -= 1000000000; - xtime.tv_sec++; - second_overflow(); - } } static inline void do_process_times(struct task_struct *p, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/MAINTAINERS linux-2.6.9/MAINTAINERS --- linux.vanilla-2.6.9/MAINTAINERS 2004-10-20 23:16:37.000000000 +0100 +++ linux-2.6.9/MAINTAINERS 2004-11-25 22:55:14.000000000 +0000 @@ -658,7 +658,7 @@ DEVICE NUMBER REGISTRY P: Torben Mathiasen M: device@lanana.org -W: http://lanana.org/docs/device-list/index.html +W: http://www.lanana.org/docs/device-list/index.html L: linux-kernel@vger.kernel.org S: Maintained diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/Makefile linux-2.6.9/Makefile --- linux.vanilla-2.6.9/Makefile 2004-10-20 23:16:37.000000000 +0100 +++ linux-2.6.9/Makefile 2004-12-10 17:59:18.000000000 +0000 @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 9 -EXTRAVERSION = -NAME=Zonked Quokka +EXTRAVERSION = -ac15 +NAME=AC 1 # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/memory.c linux-2.6.9/mm/memory.c --- linux.vanilla-2.6.9/mm/memory.c 2004-10-20 23:17:29.000000000 +0100 +++ linux-2.6.9/mm/memory.c 2004-11-25 21:36:45.000000000 +0000 @@ -326,6 +326,8 @@ pte = pte_mkold(pte); get_page(page); dst->rss++; + if (PageAnon(page)) + dst->anon_rss++; set_pte(dst_pte, pte); page_dup_rmap(page); cont_copy_pte_range_noset: @@ -416,7 +418,9 @@ set_pte(ptep, pgoff_to_pte(page->index)); if (pte_dirty(pte)) set_page_dirty(page); - if (pte_young(pte) && !PageAnon(page)) + if (PageAnon(page)) + tlb->mm->anon_rss--; + else if (pte_young(pte)) mark_page_accessed(page); tlb->freed++; page_remove_rmap(page); @@ -727,19 +731,15 @@ pte_t *pte; if (write) /* user gate pages are read-only */ return i ? : -EFAULT; - pgd = pgd_offset_gate(mm, pg); - if (!pgd) - return i ? : -EFAULT; + if (pg > TASK_SIZE) + pgd = pgd_offset_k(pg); + else + pgd = pgd_offset_gate(mm, pg); + BUG_ON(pgd_none(*pgd)); pmd = pmd_offset(pgd, pg); - if (!pmd) - return i ? : -EFAULT; + BUG_ON(pmd_none(*pmd)); pte = pte_offset_map(pmd, pg); - if (!pte) - return i ? : -EFAULT; - if (!pte_present(*pte)) { - pte_unmap(pte); - return i ? : -EFAULT; - } + BUG_ON(pte_none(*pte)); if (pages) { pages[i] = pte_page(*pte); get_page(pages[i]); @@ -753,7 +753,7 @@ continue; } - if (!vma || (pages && (vma->vm_flags & VM_IO)) + if (!vma || (vma->vm_flags & VM_IO) || !(flags & vma->vm_flags)) return i ? : -EFAULT; @@ -968,6 +968,16 @@ if (from >= end) BUG(); + /* + * Physically remapped pages are special. Tell the + * rest of the world about it: + * VM_IO tells people not to look at these pages + * (accesses can have side effects). + * VM_RESERVED tells swapout not to try to touch + * this region. + */ + vma->vm_flags |= VM_IO | VM_RESERVED; + spin_lock(&mm->page_table_lock); do { pmd_t *pmd = pmd_alloc(mm, dir, from); @@ -1095,6 +1105,8 @@ spin_lock(&mm->page_table_lock); page_table = pte_offset_map(pmd, address); if (likely(pte_same(*page_table, pte))) { + if (PageAnon(old_page)) + mm->anon_rss--; if (PageReserved(old_page)) ++mm->rss; else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/mlock.c linux-2.6.9/mm/mlock.c --- linux.vanilla-2.6.9/mm/mlock.c 2004-10-20 23:17:29.000000000 +0100 +++ linux-2.6.9/mm/mlock.c 2004-11-25 21:36:45.000000000 +0000 @@ -46,7 +46,8 @@ pages = (end - start) >> PAGE_SHIFT; if (newflags & VM_LOCKED) { pages = -pages; - ret = make_pages_present(start, end); + if (!(newflags & VM_IO)) + ret = make_pages_present(start, end); } vma->vm_mm->locked_vm -= pages; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/mmap.c linux-2.6.9/mm/mmap.c --- linux.vanilla-2.6.9/mm/mmap.c 2004-10-20 23:17:29.000000000 +0100 +++ linux-2.6.9/mm/mmap.c 2004-12-01 21:08:51.000000000 +0000 @@ -988,9 +988,12 @@ * f_op->mmap method. -DaveM */ addr = vma->vm_start; + pgoff = vma->vm_pgoff; + vm_flags = vma->vm_flags; if (!file || !vma_merge(mm, prev, addr, vma->vm_end, vma->vm_flags, NULL, file, pgoff, vma_policy(vma))) { + file = vma->vm_file; vma_link(mm, vma, prev, rb_link, rb_parent); if (correct_wcount) atomic_inc(&inode->i_writecount); @@ -1005,6 +1008,7 @@ } out: mm->total_vm += len >> PAGE_SHIFT; + __vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); if (vm_flags & VM_LOCKED) { mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); @@ -1015,7 +1019,6 @@ pgoff, flags & MAP_NONBLOCK); down_write(&mm->mmap_sem); } - __vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); return addr; unmap_and_free_vma: @@ -1868,7 +1871,7 @@ * and into the inode's i_mmap tree. If vm_file is non-NULL * then i_mmap_lock is taken here. */ -void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) +int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) { struct vm_area_struct * __vma, * prev; struct rb_node ** rb_link, * rb_parent; @@ -1891,8 +1894,9 @@ } __vma = find_vma_prepare(mm,vma->vm_start,&prev,&rb_link,&rb_parent); if (__vma && __vma->vm_start < vma->vm_end) - BUG(); + return -ENOMEM; vma_link(mm, vma, prev, rb_link, rb_parent); + return 0; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/page-writeback.c linux-2.6.9/mm/page-writeback.c --- linux.vanilla-2.6.9/mm/page-writeback.c 2004-10-20 22:31:56.000000000 +0100 +++ linux-2.6.9/mm/page-writeback.c 2004-12-10 20:46:01.000000000 +0000 @@ -276,6 +276,26 @@ } EXPORT_SYMBOL(balance_dirty_pages_ratelimited); +void throttle_vm_writeout(void) +{ + struct writeback_state wbs; + long background_thresh; + long dirty_thresh; + + for ( ; ; ) { + get_dirty_limits(&wbs, &background_thresh, &dirty_thresh); + /* + * Boost the allowable dirty threshold a bit for page + * allocators so they don't get DoS'ed by heavy writers + */ + dirty_thresh += dirty_thresh / 10; /* wheeee... */ + + if (wbs.nr_unstable + wbs.nr_writeback <= dirty_thresh) + break; + blk_congestion_wait(WRITE, HZ/10); + } +} + /* * writeback at least _min_pages, and keep writing until the amount of dirty * memory is less than the background threshold, or until we're all clean. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/rmap.c linux-2.6.9/mm/rmap.c --- linux.vanilla-2.6.9/mm/rmap.c 2004-10-20 23:17:30.000000000 +0100 +++ linux-2.6.9/mm/rmap.c 2004-11-25 21:35:42.000000000 +0000 @@ -431,6 +431,8 @@ BUG_ON(PageReserved(page)); BUG_ON(!anon_vma); + vma->vm_mm->anon_rss++; + anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; index = (address - vma->vm_start) >> PAGE_SHIFT; index += vma->vm_pgoff; @@ -578,6 +580,7 @@ swap_duplicate(entry); set_pte(pte, swp_entry_to_pte(entry)); BUG_ON(pte_file(*pte)); + mm->anon_rss--; } mm->rss--; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/shmem.c linux-2.6.9/mm/shmem.c --- linux.vanilla-2.6.9/mm/shmem.c 2004-10-20 23:17:30.000000000 +0100 +++ linux-2.6.9/mm/shmem.c 2004-11-17 19:52:23.000000000 +0000 @@ -1251,6 +1251,10 @@ case S_IFLNK: break; } + } else if (sbinfo) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); } return inode; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/slab.c linux-2.6.9/mm/slab.c --- linux.vanilla-2.6.9/mm/slab.c 2004-10-20 23:17:30.000000000 +0100 +++ linux-2.6.9/mm/slab.c 2004-11-17 19:28:50.000000000 +0000 @@ -506,7 +506,7 @@ static struct arraycache_init initarray_cache __initdata = { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; -static struct arraycache_init initarray_generic __initdata = +static struct arraycache_init initarray_generic = { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; /* internal cache of cache description objs */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/mm/vmscan.c linux-2.6.9/mm/vmscan.c --- linux.vanilla-2.6.9/mm/vmscan.c 2004-10-20 23:17:30.000000000 +0100 +++ linux-2.6.9/mm/vmscan.c 2004-12-10 20:46:41.000000000 +0000 @@ -825,6 +825,8 @@ break; } } + + throttle_vm_writeout(); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/802/tr.c linux-2.6.9/net/802/tr.c --- linux.vanilla-2.6.9/net/802/tr.c 2004-10-20 22:31:59.000000000 +0100 +++ linux-2.6.9/net/802/tr.c 2004-11-25 20:55:09.000000000 +0000 @@ -250,10 +250,11 @@ unsigned int hash; struct rif_cache_s *entry; unsigned char *olddata; + unsigned long flags; static const unsigned char mcast_func_addr[] = {0xC0,0x00,0x00,0x04,0x00,0x00}; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Broadcasts are single route as stated in RFC 1042 @@ -322,7 +323,7 @@ else slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); olddata = skb->data; - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); skb_pull(skb, slack); memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); @@ -336,10 +337,11 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) { unsigned int hash, rii_p = 0; + unsigned long flags; struct rif_cache_s *entry; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Firstly see if the entry exists @@ -377,7 +379,7 @@ if(!entry) { printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n"); - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); return; } @@ -419,7 +421,7 @@ } entry->last_used=jiffies; } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); } /* @@ -429,9 +431,9 @@ static void rif_check_expire(unsigned long dummy) { int i; - unsigned long next_interval = jiffies + sysctl_tr_rif_timeout/2; + unsigned long flags, next_interval = jiffies + sysctl_tr_rif_timeout/2; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); for(i =0; i < RIF_TABLE_SIZE; i++) { struct rif_cache_s *entry, **pentry; @@ -453,7 +455,7 @@ } } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); mod_timer(&rif_timer, next_interval); @@ -484,7 +486,7 @@ static void *rif_seq_start(struct seq_file *seq, loff_t *pos) { - spin_lock_bh(&rif_lock); + spin_lock_irq(&rif_lock); return *pos ? rif_get_idx(*pos - 1) : SEQ_START_TOKEN; } @@ -515,7 +517,7 @@ static void rif_seq_stop(struct seq_file *seq, void *v) { - spin_unlock_bh(&rif_lock); + spin_unlock_irq(&rif_lock); } static int rif_seq_show(struct seq_file *seq, void *v) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/appletalk/ddp.c linux-2.6.9/net/appletalk/ddp.c --- linux.vanilla-2.6.9/net/appletalk/ddp.c 2004-10-20 23:17:30.000000000 +0100 +++ linux-2.6.9/net/appletalk/ddp.c 2004-11-17 19:26:32.000000000 +0000 @@ -570,7 +570,7 @@ retval = -ENOBUFS; if (!rt) - goto out; + goto out_unlock; memset(rt, 0, sizeof(*rt)); rt->next = atalk_routes; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/compat.c linux-2.6.9/net/compat.c --- linux.vanilla-2.6.9/net/compat.c 2004-10-20 23:17:31.000000000 +0100 +++ linux-2.6.9/net/compat.c 2004-12-10 20:36:02.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -123,6 +124,12 @@ (struct compat_cmsghdr __user *)((msg)->msg_control) : \ (struct compat_cmsghdr __user *)NULL) +#define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \ + ((ucmlen) >= sizeof(struct cmsghdr) && \ + (ucmlen) <= (unsigned long) \ + ((mhdr)->msg_controllen - \ + ((char *)(ucmsg) - (char *)(mhdr)->msg_control))) + static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg, struct compat_cmsghdr __user *cmsg, int cmsg_len) { @@ -153,11 +160,7 @@ return -EFAULT; /* Catch bogons. */ - if(CMSG_COMPAT_ALIGN(ucmlen) < - CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))) - return -EINVAL; - if((unsigned long)(((char __user *)ucmsg - (char __user *)kmsg->msg_control) - + ucmlen) > kmsg->msg_controllen) + if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg)) return -EINVAL; tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) + @@ -264,6 +267,9 @@ for (i = 0, cmfptr = (int __user *) CMSG_COMPAT_DATA(cm); i < fdmax; i++, cmfptr++) { int new_fd; + err = security_file_receive(fp[i]); + if (err) + break; err = get_unused_fd(); if (err < 0) break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/core/neighbour.c linux-2.6.9/net/core/neighbour.c --- linux.vanilla-2.6.9/net/core/neighbour.c 2004-10-20 23:17:31.000000000 +0100 +++ linux-2.6.9/net/core/neighbour.c 2004-11-15 16:09:17.000000000 +0000 @@ -254,18 +254,20 @@ { struct neighbour *n = NULL; unsigned long now = jiffies; + int entries; - if (tbl->entries > tbl->gc_thresh3 || - (tbl->entries > tbl->gc_thresh2 && + entries = atomic_inc_return(&tbl->entries) - 1; + if (entries >= tbl->gc_thresh3 || + (entries >= tbl->gc_thresh2 && time_after(now, tbl->last_flush + 5 * HZ))) { if (!neigh_forced_gc(tbl) && - tbl->entries > tbl->gc_thresh3) - goto out; + entries >= tbl->gc_thresh3) + goto out_entries; } n = kmem_cache_alloc(tbl->kmem_cachep, SLAB_ATOMIC); if (!n) - goto out; + goto out_entries; memset(n, 0, tbl->entry_size); @@ -281,12 +283,15 @@ NEIGH_CACHE_STAT_INC(tbl, allocs); neigh_glbl_allocs++; - tbl->entries++; n->tbl = tbl; atomic_set(&n->refcnt, 1); n->dead = 1; out: return n; + +out_entries: + atomic_dec(&tbl->entries); + goto out; } static struct neighbour **neigh_hash_alloc(unsigned int entries) @@ -427,7 +432,7 @@ write_lock_bh(&tbl->lock); - if (tbl->entries > (tbl->hash_mask + 1)) + if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1)) neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1); hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; @@ -608,7 +613,7 @@ NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh); neigh_glbl_allocs--; - neigh->tbl->entries--; + atomic_dec(&neigh->tbl->entries); kmem_cache_free(neigh->tbl->kmem_cachep, neigh); } @@ -1394,7 +1399,7 @@ del_timer_sync(&tbl->proxy_timer); pneigh_queue_purge(&tbl->proxy_queue); neigh_ifdown(tbl, NULL); - if (tbl->entries) + if (atomic_read(&tbl->entries)) printk(KERN_CRIT "neighbour leakage\n"); write_lock(&neigh_tbl_lock); for (tp = &neigh_tables; *tp; tp = &(*tp)->next) { @@ -1951,7 +1956,7 @@ seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " "%08lx %08lx %08lx %08lx\n", - tbl->entries, + atomic_read(&tbl->entries), st->allocs, st->destroys, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/core/scm.c linux-2.6.9/net/core/scm.c --- linux.vanilla-2.6.9/net/core/scm.c 2004-10-20 22:31:58.000000000 +0100 +++ linux-2.6.9/net/core/scm.c 2004-12-10 20:36:00.000000000 +0000 @@ -127,9 +127,7 @@ for too short ancillary data object at all! Oops. OK, let's add it... */ - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) + if (!CMSG_OK(msg, cmsg)) goto error; if (cmsg->cmsg_level != SOL_SOCKET) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/core/skbuff.c linux-2.6.9/net/core/skbuff.c --- linux.vanilla-2.6.9/net/core/skbuff.c 2004-10-20 23:17:31.000000000 +0100 +++ linux-2.6.9/net/core/skbuff.c 2004-10-21 17:54:40.000000000 +0100 @@ -394,6 +394,8 @@ new->tc_index = old->tc_index; #endif atomic_set(&new->users, 1); + skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size; + skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs; } /** @@ -483,8 +485,6 @@ } skb_shinfo(n)->nr_frags = i; } - skb_shinfo(n)->tso_size = skb_shinfo(skb)->tso_size; - skb_shinfo(n)->tso_segs = skb_shinfo(skb)->tso_segs; if (skb_shinfo(skb)->frag_list) { skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; @@ -631,8 +631,6 @@ BUG(); copy_skb_header(n, skb); - skb_shinfo(n)->tso_size = skb_shinfo(skb)->tso_size; - skb_shinfo(n)->tso_segs = skb_shinfo(skb)->tso_segs; return n; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/fib_semantics.c linux-2.6.9/net/ipv4/fib_semantics.c --- linux.vanilla-2.6.9/net/ipv4/fib_semantics.c 2004-10-20 23:17:31.000000000 +0100 +++ linux-2.6.9/net/ipv4/fib_semantics.c 2004-11-18 14:13:27.000000000 +0000 @@ -163,6 +163,8 @@ if (fi->fib_prefsrc) hlist_del(&fi->fib_lhash); change_nexthops(fi) { + if (!nh->nh_dev) + continue; hlist_del(&nh->nh_hash); } endfor_nexthops(fi) fi->fib_dead = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/ip_options.c linux-2.6.9/net/ipv4/ip_options.c --- linux.vanilla-2.6.9/net/ipv4/ip_options.c 2004-10-20 22:31:56.000000000 +0100 +++ linux-2.6.9/net/ipv4/ip_options.c 2004-12-10 20:32:45.000000000 +0000 @@ -515,6 +515,8 @@ kfree(opt); return -EINVAL; } + if (*optp) + kfree(*optp); *optp = opt; return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/ip_output.c linux-2.6.9/net/ipv4/ip_output.c --- linux.vanilla-2.6.9/net/ipv4/ip_output.c 2004-10-20 23:17:31.000000000 +0100 +++ linux-2.6.9/net/ipv4/ip_output.c 2004-11-25 21:05:56.000000000 +0000 @@ -279,7 +279,7 @@ newskb->dev, ip_dev_loopback_xmit); } - if (skb->len > dst_pmtu(&rt->u.dst) || skb_shinfo(skb)->frag_list) + if (skb->len > dst_pmtu(&rt->u.dst)) return ip_fragment(skb, ip_finish_output); else return ip_finish_output(skb); @@ -291,8 +291,7 @@ IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); - if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list) && - !skb_shinfo(skb)->tso_size) + if (skb->len > dst_pmtu(skb->dst) && !skb_shinfo(skb)->tso_size) return ip_fragment(skb, ip_finish_output); else return ip_finish_output(skb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/ip_sockglue.c linux-2.6.9/net/ipv4/ip_sockglue.c --- linux.vanilla-2.6.9/net/ipv4/ip_sockglue.c 2004-10-20 22:31:56.000000000 +0100 +++ linux-2.6.9/net/ipv4/ip_sockglue.c 2004-12-10 20:36:00.000000000 +0000 @@ -146,11 +146,8 @@ struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) { + if (!CMSG_OK(msg, cmsg)) return -EINVAL; - } if (cmsg->cmsg_level != SOL_IP) continue; switch (cmsg->cmsg_type) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.6.9/net/ipv4/netfilter/ip_conntrack_ftp.c --- linux.vanilla-2.6.9/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-10-20 23:17:32.000000000 +0100 +++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-12-10 20:33:15.000000000 +0000 @@ -381,6 +381,7 @@ problem (DMZ machines opening holes to internal networks, or the packet filter itself). */ if (!loose) { + ip_conntrack_expect_put(exp); ret = NF_ACCEPT; goto out; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux.vanilla-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-10-20 23:17:32.000000000 +0100 +++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-12-10 20:29:06.000000000 +0000 @@ -816,7 +816,7 @@ #ifdef CONFIG_PROC_FS proc_net_remove("ip_conntrack_stat"); cleanup_proc_exp: - proc_net_remove("ip_conntrack_exp"); + proc_net_remove("ip_conntrack_expect"); cleanup_proc: proc_net_remove("ip_conntrack"); cleanup_init: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/tcp_input.c linux-2.6.9/net/ipv4/tcp_input.c --- linux.vanilla-2.6.9/net/ipv4/tcp_input.c 2004-10-20 23:17:32.000000000 +0100 +++ linux-2.6.9/net/ipv4/tcp_input.c 2004-11-18 14:14:11.000000000 +0000 @@ -2369,25 +2369,19 @@ { struct tcp_opt *tp = tcp_sk(sk); struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - __u32 mss = tcp_skb_mss(skb); - __u32 snd_una = tp->snd_una; - __u32 orig_seq, seq; - __u32 packets_acked = 0; + __u32 seq = tp->snd_una; + __u32 packets_acked; int acked = 0; /* If we get here, the whole TSO packet has not been * acked. */ - BUG_ON(!after(scb->end_seq, snd_una)); + BUG_ON(!after(scb->end_seq, seq)); - seq = orig_seq = scb->seq; - while (!after(seq + mss, snd_una)) { - packets_acked++; - seq += mss; - } - - if (tcp_trim_head(sk, skb, (seq - orig_seq))) + packets_acked = tcp_skb_pcount(skb); + if (tcp_trim_head(sk, skb, seq - scb->seq)) return 0; + packets_acked -= tcp_skb_pcount(skb); if (packets_acked) { __u8 sacked = scb->sacked; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv4/tcp_output.c linux-2.6.9/net/ipv4/tcp_output.c --- linux.vanilla-2.6.9/net/ipv4/tcp_output.c 2004-10-20 23:17:32.000000000 +0100 +++ linux-2.6.9/net/ipv4/tcp_output.c 2004-11-18 14:14:11.000000000 +0000 @@ -455,9 +455,13 @@ { struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *buff; - int nsize = skb->len - len; + int nsize; u16 flags; + nsize = skb_headlen(skb) - len; + if (nsize < 0) + nsize = 0; + if (skb_cloned(skb) && skb_is_nonlinear(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) @@ -562,8 +566,6 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) { - struct tcp_opt *tp = tcp_sk(sk); - if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) return -ENOMEM; @@ -586,7 +588,8 @@ /* Any change of skb->len requires recalculation of tso * factor and mss. */ - tcp_set_skb_tso_segs(skb, tp->mss_cache_std); + if (tcp_skb_pcount(skb) > 1) + tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv6/datagram.c linux-2.6.9/net/ipv6/datagram.c --- linux.vanilla-2.6.9/net/ipv6/datagram.c 2004-10-20 23:17:34.000000000 +0100 +++ linux-2.6.9/net/ipv6/datagram.c 2004-12-10 20:36:00.000000000 +0000 @@ -427,9 +427,7 @@ int addr_type; struct net_device *dev = NULL; - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) { + if (!CMSG_OK(msg, cmsg)) { err = -EINVAL; goto exit_f; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv6/ip6_output.c linux-2.6.9/net/ipv6/ip6_output.c --- linux.vanilla-2.6.9/net/ipv6/ip6_output.c 2004-10-20 23:17:34.000000000 +0100 +++ linux-2.6.9/net/ipv6/ip6_output.c 2004-11-25 21:05:56.000000000 +0000 @@ -150,7 +150,7 @@ { struct sk_buff *skb = *pskb; - if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list)) + if (skb->len > dst_pmtu(skb->dst)) return ip6_fragment(pskb, ip6_output2); else return ip6_output2(pskb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/ipv6/xfrm6_output.c linux-2.6.9/net/ipv6/xfrm6_output.c --- linux.vanilla-2.6.9/net/ipv6/xfrm6_output.c 2004-10-20 23:17:34.000000000 +0100 +++ linux-2.6.9/net/ipv6/xfrm6_output.c 2004-11-25 21:13:42.000000000 +0000 @@ -79,7 +79,7 @@ int mtu, ret = 0; struct dst_entry *dst = skb->dst; - mtu = dst_pmtu(dst) - sizeof(struct ipv6hdr); + mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len; if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/netlink/af_netlink.c linux-2.6.9/net/netlink/af_netlink.c --- linux.vanilla-2.6.9/net/netlink/af_netlink.c 2004-10-20 23:17:34.000000000 +0100 +++ linux-2.6.9/net/netlink/af_netlink.c 2004-11-18 14:12:33.000000000 +0000 @@ -44,6 +44,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -56,9 +62,9 @@ struct netlink_opt { u32 pid; - unsigned groups; + unsigned int groups; u32 dst_pid; - unsigned dst_groups; + unsigned int dst_groups; unsigned long state; int (*handler)(int unit, struct sk_buff *skb); wait_queue_head_t wait; @@ -69,9 +75,28 @@ #define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo) -static struct hlist_head nl_table[MAX_LINKS]; +struct nl_pid_hash { + struct hlist_head *table; + unsigned long rehash_time; + + unsigned int mask; + unsigned int shift; + + unsigned int entries; + unsigned int max_shift; + + u32 rnd; +}; + +struct netlink_table { + struct nl_pid_hash hash; + struct hlist_head mc_list; +}; + +static struct netlink_table *nl_table; + static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); -static unsigned nl_nonroot[MAX_LINKS]; +static unsigned int nl_nonroot[MAX_LINKS]; #ifdef NL_EMULATE_DEV static struct socket *netlink_kernel[MAX_LINKS]; @@ -80,13 +105,16 @@ static int netlink_dump(struct sock *sk); static void netlink_destroy_callback(struct netlink_callback *cb); -atomic_t netlink_sock_nr; - static rwlock_t nl_table_lock = RW_LOCK_UNLOCKED; static atomic_t nl_table_users = ATOMIC_INIT(0); static struct notifier_block *netlink_chain; +static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid) +{ + return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask]; +} + static void netlink_sock_destruct(struct sock *sk) { skb_queue_purge(&sk->sk_receive_queue); @@ -100,11 +128,6 @@ BUG_TRAP(!nlk_sk(sk)->cb); kfree(nlk_sk(sk)); - - atomic_dec(&netlink_sock_nr); -#ifdef NETLINK_REFCNT_DEBUG - printk(KERN_DEBUG "NETLINK %p released, %d are still alive\n", sk, atomic_read(&netlink_sock_nr)); -#endif } /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. @@ -160,11 +183,14 @@ static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) { + struct nl_pid_hash *hash = &nl_table[protocol].hash; + struct hlist_head *head; struct sock *sk; struct hlist_node *node; read_lock(&nl_table_lock); - sk_for_each(sk, node, &nl_table[protocol]) { + head = nl_pid_hashfn(hash, pid); + sk_for_each(sk, node, head) { if (nlk_sk(sk)->pid == pid) { sock_hold(sk); goto found; @@ -176,27 +202,118 @@ return sk; } +static inline struct hlist_head *nl_pid_hash_alloc(size_t size) +{ + if (size <= PAGE_SIZE) + return kmalloc(size, GFP_ATOMIC); + else + return (struct hlist_head *) + __get_free_pages(GFP_ATOMIC, get_order(size)); +} + +static inline void nl_pid_hash_free(struct hlist_head *table, size_t size) +{ + if (size <= PAGE_SIZE) + kfree(table); + else + free_pages((unsigned long)table, get_order(size)); +} + +static int nl_pid_hash_rehash(struct nl_pid_hash *hash, int grow) +{ + unsigned int omask, mask, shift; + size_t osize, size; + struct hlist_head *otable, *table; + int i; + + omask = mask = hash->mask; + osize = size = (mask + 1) * sizeof(*table); + shift = hash->shift; + + if (grow) { + if (++shift > hash->max_shift) + return 0; + mask = mask * 2 + 1; + size *= 2; + } + + table = nl_pid_hash_alloc(size); + if (!table) + return 0; + + memset(table, 0, size); + otable = hash->table; + hash->table = table; + hash->mask = mask; + hash->shift = shift; + get_random_bytes(&hash->rnd, sizeof(hash->rnd)); + + for (i = 0; i <= omask; i++) { + struct sock *sk; + struct hlist_node *node, *tmp; + + sk_for_each_safe(sk, node, tmp, &otable[i]) + __sk_add_node(sk, nl_pid_hashfn(hash, nlk_sk(sk)->pid)); + } + + nl_pid_hash_free(otable, osize); + hash->rehash_time = jiffies + 10 * 60 * HZ; + return 1; +} + +static inline int nl_pid_hash_dilute(struct nl_pid_hash *hash, int len) +{ + int avg = hash->entries >> hash->shift; + + if (unlikely(avg > 1) && nl_pid_hash_rehash(hash, 1)) + return 1; + + if (unlikely(len > avg) && time_after(jiffies, hash->rehash_time)) { + nl_pid_hash_rehash(hash, 0); + return 1; + } + + return 0; +} + static struct proto_ops netlink_ops; static int netlink_insert(struct sock *sk, u32 pid) { + struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; + struct hlist_head *head; int err = -EADDRINUSE; struct sock *osk; struct hlist_node *node; + int len; netlink_table_grab(); - sk_for_each(osk, node, &nl_table[sk->sk_protocol]) { + head = nl_pid_hashfn(hash, pid); + len = 0; + sk_for_each(osk, node, head) { if (nlk_sk(osk)->pid == pid) break; + len++; } - if (!node) { - err = -EBUSY; - if (nlk_sk(sk)->pid == 0) { - nlk_sk(sk)->pid = pid; - sk_add_node(sk, &nl_table[sk->sk_protocol]); - err = 0; - } - } + if (node) + goto err; + + err = -EBUSY; + if (nlk_sk(sk)->pid) + goto err; + + err = -ENOMEM; + if (BITS_PER_LONG > 32 && unlikely(hash->entries >= UINT_MAX)) + goto err; + + if (len && nl_pid_hash_dilute(hash, len)) + head = nl_pid_hashfn(hash, pid); + hash->entries++; + nlk_sk(sk)->pid = pid; + sk_add_node(sk, head); + err = 0; + +err: netlink_table_ungrab(); return err; } @@ -204,7 +321,10 @@ static void netlink_remove(struct sock *sk) { netlink_table_grab(); + nl_table[sk->sk_protocol].hash.entries--; sk_del_node_init(sk); + if (nlk_sk(sk)->groups) + __sk_del_bind_node(sk); netlink_table_ungrab(); } @@ -240,7 +360,6 @@ spin_lock_init(&nlk->cb_lock); init_waitqueue_head(&nlk->wait); sk->sk_destruct = netlink_sock_destruct; - atomic_inc(&netlink_sock_nr); sk->sk_protocol = protocol; return 0; @@ -290,19 +409,24 @@ static int netlink_autobind(struct socket *sock) { struct sock *sk = sock->sk; + struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; + struct hlist_head *head; struct sock *osk; struct hlist_node *node; s32 pid = current->pid; int err; + static s32 rover = -4097; retry: + cond_resched(); netlink_table_grab(); - sk_for_each(osk, node, &nl_table[sk->sk_protocol]) { + head = nl_pid_hashfn(hash, pid); + sk_for_each(osk, node, head) { if (nlk_sk(osk)->pid == pid) { /* Bind collision, search negative pid values. */ - if (pid > 0) - pid = -4096; - pid--; + pid = rover--; + if (rover > -4097) + rover = -4097; netlink_table_ungrab(); goto retry; } @@ -316,7 +440,7 @@ return 0; } -static inline int netlink_capable(struct socket *sock, unsigned flag) +static inline int netlink_capable(struct socket *sock, unsigned int flag) { return (nl_nonroot[sock->sk->sk_protocol] & flag) || capable(CAP_NET_ADMIN); @@ -339,21 +463,26 @@ if (nlk->pid) { if (nladdr->nl_pid != nlk->pid) return -EINVAL; - nlk->groups = nladdr->nl_groups; - return 0; + } else { + err = nladdr->nl_pid ? + netlink_insert(sk, nladdr->nl_pid) : + netlink_autobind(sock); + if (err) + return err; } - if (nladdr->nl_pid == 0) { - err = netlink_autobind(sock); - if (err == 0) - nlk->groups = nladdr->nl_groups; - return err; - } + if (!nladdr->nl_groups && !nlk->groups) + return 0; - err = netlink_insert(sk, nladdr->nl_pid); - if (err == 0) - nlk->groups = nladdr->nl_groups; - return err; + netlink_table_grab(); + if (nlk->groups && !nladdr->nl_groups) + __sk_del_bind_node(sk); + else if (!nlk->groups && nladdr->nl_groups) + sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); + nlk->groups = nladdr->nl_groups; + netlink_table_ungrab(); + + return 0; } static int netlink_connect(struct socket *sock, struct sockaddr *addr, @@ -593,19 +722,81 @@ skb_set_owner_r(skb, sk); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); - return 0; + return atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf; } return -1; } +struct netlink_broadcast_data { + struct sock *exclude_sk; + u32 pid; + u32 group; + int failure; + int congested; + int delivered; + int allocation; + struct sk_buff *skb, *skb2; +}; + +static inline int do_one_broadcast(struct sock *sk, + struct netlink_broadcast_data *p) +{ + struct netlink_opt *nlk = nlk_sk(sk); + int val; + + if (p->exclude_sk == sk) + goto out; + + if (nlk->pid == p->pid || !(nlk->groups & p->group)) + goto out; + + if (p->failure) { + netlink_overrun(sk); + goto out; + } + + sock_hold(sk); + if (p->skb2 == NULL) { + if (atomic_read(&p->skb->users) != 1) { + p->skb2 = skb_clone(p->skb, p->allocation); + } else { + p->skb2 = p->skb; + atomic_inc(&p->skb->users); + } + } + if (p->skb2 == NULL) { + netlink_overrun(sk); + /* Clone failed. Notify ALL listeners. */ + p->failure = 1; + } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { + netlink_overrun(sk); + } else { + p->congested |= val; + p->delivered = 1; + p->skb2 = NULL; + } + sock_put(sk); + +out: + return 0; +} + int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, int allocation) { - struct sock *sk; + struct netlink_broadcast_data info; struct hlist_node *node; - struct sk_buff *skb2 = NULL; - int protocol = ssk->sk_protocol; - int failure = 0, delivered = 0; + struct sock *sk; + + info.exclude_sk = ssk; + info.pid = pid; + info.group = group; + info.failure = 0; + info.congested = 0; + info.delivered = 0; + info.allocation = allocation; + info.skb = skb; + info.skb2 = NULL; netlink_trim(skb, allocation); @@ -613,73 +804,65 @@ netlink_lock_table(); - sk_for_each(sk, node, &nl_table[protocol]) { - struct netlink_opt *nlk = nlk_sk(sk); - - if (ssk == sk) - continue; - - if (nlk->pid == pid || !(nlk->groups & group)) - continue; - - if (failure) { - netlink_overrun(sk); - continue; - } - - sock_hold(sk); - if (skb2 == NULL) { - if (atomic_read(&skb->users) != 1) { - skb2 = skb_clone(skb, allocation); - } else { - skb2 = skb; - atomic_inc(&skb->users); - } - } - if (skb2 == NULL) { - netlink_overrun(sk); - /* Clone failed. Notify ALL listeners. */ - failure = 1; - } else if (netlink_broadcast_deliver(sk, skb2)) { - netlink_overrun(sk); - } else { - delivered = 1; - skb2 = NULL; - } - sock_put(sk); - } + sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) + do_one_broadcast(sk, &info); netlink_unlock_table(); - if (skb2) - kfree_skb(skb2); + if (info.skb2) + kfree_skb(info.skb2); kfree_skb(skb); - if (delivered) + if (info.delivered) { + if (info.congested && (allocation & __GFP_WAIT)) + yield(); return 0; - if (failure) + } + if (info.failure) return -ENOBUFS; return -ESRCH; } +struct netlink_set_err_data { + struct sock *exclude_sk; + u32 pid; + u32 group; + int code; +}; + +static inline int do_one_set_err(struct sock *sk, + struct netlink_set_err_data *p) +{ + struct netlink_opt *nlk = nlk_sk(sk); + + if (sk == p->exclude_sk) + goto out; + + if (nlk->pid == p->pid || !(nlk->groups & p->group)) + goto out; + + sk->sk_err = p->code; + sk->sk_error_report(sk); +out: + return 0; +} + void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) { - struct sock *sk; + struct netlink_set_err_data info; struct hlist_node *node; - int protocol = ssk->sk_protocol; + struct sock *sk; + + info.exclude_sk = ssk; + info.pid = pid; + info.group = group; + info.code = code; read_lock(&nl_table_lock); - sk_for_each(sk, node, &nl_table[protocol]) { - struct netlink_opt *nlk = nlk_sk(sk); - if (ssk == sk) - continue; - if (nlk->pid == pid || !(nlk->groups & group)) - continue; + sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) + do_one_set_err(sk, &info); - sk->sk_err = code; - sk->sk_error_report(sk); - } read_unlock(&nl_table_lock); } @@ -855,6 +1038,9 @@ struct socket *sock; struct sock *sk; + if (!nl_table) + return NULL; + if (unit<0 || unit>=MAX_LINKS) return NULL; @@ -870,13 +1056,16 @@ if (input) nlk_sk(sk)->data_ready = input; - netlink_insert(sk, 0); + if (netlink_insert(sk, 0)) { + sock_release(sock); + return NULL; + } return sk; } -void netlink_set_nonroot(int protocol, unsigned flags) +void netlink_set_nonroot(int protocol, unsigned int flags) { - if ((unsigned)protocol < MAX_LINKS) + if ((unsigned int)protocol < MAX_LINKS) nl_nonroot[protocol] = flags; } @@ -1069,20 +1258,31 @@ #endif #ifdef CONFIG_PROC_FS +struct nl_seq_iter { + int link; + int hash_idx; +}; + static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) { - long i; + struct nl_seq_iter *iter = seq->private; + int i, j; struct sock *s; struct hlist_node *node; loff_t off = 0; for (i=0; iprivate = (void *) i; - return s; + struct nl_pid_hash *hash = &nl_table[i].hash; + + for (j = 0; j <= hash->mask; j++) { + sk_for_each(s, node, &hash->table[j]) { + if (off == pos) { + iter->link = i; + iter->hash_idx = j; + return s; + } + ++off; } - ++off; } } return NULL; @@ -1097,6 +1297,8 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct sock *s; + struct nl_seq_iter *iter; + int i, j; ++*pos; @@ -1104,18 +1306,29 @@ return netlink_seq_socket_idx(seq, 0); s = sk_next(v); - if (!s) { - long i = (long)seq->private; + if (s) + return s; + + iter = seq->private; + i = iter->link; + j = iter->hash_idx + 1; - while (++i < MAX_LINKS) { - s = sk_head(&nl_table[i]); + do { + struct nl_pid_hash *hash = &nl_table[i].hash; + + for (; j <= hash->mask; j++) { + s = sk_head(&hash->table[j]); if (s) { - seq->private = (void *) i; - break; + iter->link = i; + iter->hash_idx = j; + return s; } } - } - return s; + + j = 0; + } while (++i < MAX_LINKS); + + return NULL; } static void netlink_seq_stop(struct seq_file *seq, void *v) @@ -1159,7 +1372,24 @@ static int netlink_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &netlink_seq_ops); + struct seq_file *seq; + struct nl_seq_iter *iter; + int err; + + iter = kmalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + + err = seq_open(file, &netlink_seq_ops); + if (err) { + kfree(iter); + return err; + } + + memset(iter, 0, sizeof(*iter)); + seq = file->private_data; + seq->private = iter; + return 0; } static struct file_operations netlink_seq_fops = { @@ -1167,7 +1397,7 @@ .open = netlink_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_private, }; #endif @@ -1209,14 +1439,54 @@ .owner = THIS_MODULE, /* for consistency 8) */ }; +extern void netlink_skb_parms_too_large(void); + static int __init netlink_proto_init(void) { struct sk_buff *dummy_skb; + int i; + unsigned long max; + unsigned int order; + + if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)) + netlink_skb_parms_too_large(); + + nl_table = kmalloc(sizeof(*nl_table) * MAX_LINKS, GFP_KERNEL); + if (!nl_table) { +enomem: + printk(KERN_CRIT "netlink_init: Cannot allocate nl_table\n"); + return -ENOMEM; + } + + memset(nl_table, 0, sizeof(*nl_table) * MAX_LINKS); - if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)) { - printk(KERN_CRIT "netlink_init: panic\n"); - return -1; + if (num_physpages >= (128 * 1024)) + max = num_physpages >> (21 - PAGE_SHIFT); + else + max = num_physpages >> (23 - PAGE_SHIFT); + + order = get_bitmask_order(max) - 1 + PAGE_SHIFT; + max = (1UL << order) / sizeof(struct hlist_head); + order = get_bitmask_order(max > UINT_MAX ? UINT_MAX : max) - 1; + + for (i = 0; i < MAX_LINKS; i++) { + struct nl_pid_hash *hash = &nl_table[i].hash; + + hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); + if (!hash->table) { + while (i-- > 0) + nl_pid_hash_free(nl_table[i].hash.table, + 1 * sizeof(*hash->table)); + kfree(nl_table); + goto enomem; + } + memset(hash->table, 0, 1 * sizeof(*hash->table)); + hash->max_shift = order; + hash->shift = 0; + hash->mask = 0; + hash->rehash_time = jiffies; } + sock_register(&netlink_family_ops); #ifdef CONFIG_PROC_FS proc_net_fops_create("netlink", 0, &netlink_seq_fops); @@ -1230,6 +1500,8 @@ { sock_unregister(PF_NETLINK); proc_net_remove("netlink"); + kfree(nl_table); + nl_table = NULL; } core_initcall(netlink_proto_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/sctp/socket.c linux-2.6.9/net/sctp/socket.c --- linux.vanilla-2.6.9/net/sctp/socket.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/net/sctp/socket.c 2004-12-10 20:36:00.000000000 +0000 @@ -4051,12 +4051,8 @@ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { - /* Check for minimum length. The SCM code has this check. */ - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) { + if (!CMSG_OK(msg, cmsg)) return -EINVAL; - } /* Should we parse this header or ignore? */ if (cmsg->cmsg_level != IPPROTO_SCTP) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/sunrpc/svcauth_unix.c linux-2.6.9/net/sunrpc/svcauth_unix.c --- linux.vanilla-2.6.9/net/sunrpc/svcauth_unix.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/net/sunrpc/svcauth_unix.c 2004-10-28 00:17:27.000000000 +0100 @@ -150,11 +150,13 @@ } static struct ip_map *ip_map_lookup(struct ip_map *, int); +#define DOMAINNAME_MAX 1024 /* FQDN + possible aliases/subnets/wildcards */ +#define CLASS_MAX 50 static int ip_map_parse(struct cache_detail *cd, char *mesg, int mlen) { /* class ipaddress [domainname] */ - char class[50], buf[50]; + static char class[CLASS_MAX], buf[DOMAINNAME_MAX]; int len; int b1,b2,b3,b4; char c; @@ -167,13 +169,13 @@ mesg[mlen-1] = 0; /* class */ - len = qword_get(&mesg, class, 50); + len = qword_get(&mesg, class, CLASS_MAX); if (len <= 0) return -EINVAL; if (len >= sizeof(ipm.m_class)) return -EINVAL; /* ip address */ - len = qword_get(&mesg, buf, 50); + len = qword_get(&mesg, buf, DOMAINNAME_MAX); if (len <= 0) return -EINVAL; if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) @@ -184,7 +186,7 @@ return -EINVAL; /* domainname, or empty for NEGATIVE */ - len = qword_get(&mesg, buf, 50); + len = qword_get(&mesg, buf, DOMAINNAME_MAX); if (len < 0) return -EINVAL; if (len) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/unix/af_unix.c linux-2.6.9/net/unix/af_unix.c --- linux.vanilla-2.6.9/net/unix/af_unix.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/net/unix/af_unix.c 2004-11-19 17:20:02.000000000 +0000 @@ -477,6 +477,8 @@ struct msghdr *, size_t, int); static int unix_dgram_connect(struct socket *, struct sockaddr *, int, int); +static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *, + struct msghdr *, size_t); static struct proto_ops unix_stream_ops = { .family = PF_UNIX, @@ -535,7 +537,7 @@ .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, .getsockopt = sock_no_getsockopt, - .sendmsg = unix_dgram_sendmsg, + .sendmsg = unix_seqpacket_sendmsg, .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, @@ -1365,9 +1367,11 @@ if (other->sk_shutdown & RCV_SHUTDOWN) goto out_unlock; - err = security_unix_may_send(sk->sk_socket, other->sk_socket); - if (err) - goto out_unlock; + if (sk->sk_type != SOCK_SEQPACKET) { + err = security_unix_may_send(sk->sk_socket, other->sk_socket); + if (err) + goto out_unlock; + } if (unix_peer(other) != sk && (skb_queue_len(&other->sk_receive_queue) > @@ -1517,6 +1521,25 @@ return sent ? : err; } +static int unix_seqpacket_sendmsg(struct kiocb *kiocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ + int err; + struct sock *sk = sock->sk; + + err = sock_error(sk); + if (err) + return err; + + if (sk->sk_state != TCP_ESTABLISHED) + return -ENOTCONN; + + if (msg->msg_namelen) + msg->msg_namelen = 0; + + return unix_dgram_sendmsg(kiocb, sock, msg, len); +} + static void unix_copy_addr(struct msghdr *msg, struct sock *sk) { struct unix_sock *u = unix_sk(sk); @@ -1546,9 +1569,11 @@ msg->msg_namelen = 0; + down(&u->readsem); + skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) - goto out; + goto out_unlock; wake_up_interruptible(&u->peer_wait); @@ -1598,6 +1623,8 @@ out_free: skb_free_datagram(sk,skb); +out_unlock: + up(&u->readsem); out: return err; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/net/xfrm/xfrm_policy.c linux-2.6.9/net/xfrm/xfrm_policy.c --- linux.vanilla-2.6.9/net/xfrm/xfrm_policy.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/net/xfrm/xfrm_policy.c 2004-12-10 20:42:09.000000000 +0000 @@ -332,7 +332,7 @@ struct xfrm_policy **newpos = NULL; write_lock_bh(&xfrm_policy_lock); - for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { + for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) { if (excl) { write_unlock_bh(&xfrm_policy_lock); @@ -342,12 +342,15 @@ delpol = pol; if (policy->priority > pol->priority) continue; - } else if (policy->priority >= pol->priority) + } else if (policy->priority >= pol->priority) { + p = &pol->next; continue; + } if (!newpos) newpos = p; if (delpol) break; + p = &pol->next; } if (newpos) p = newpos; @@ -893,6 +896,16 @@ return 0; } +static inline int secpath_has_tunnel(struct sec_path *sp, int k) +{ + for (; k < sp->len; k++) { + if (sp->x[k].xvec->props.mode) + return 1; + } + + return 0; +} + int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) { @@ -930,7 +943,7 @@ xfrm_policy_lookup); if (!pol) - return !skb->sp; + return !skb->sp || !secpath_has_tunnel(skb->sp, 0); pol->curlft.use_time = (unsigned long)xtime.tv_sec; @@ -954,10 +967,8 @@ goto reject; } - for (; k < sp->len; k++) { - if (sp->x[k].xvec->props.mode) - goto reject; - } + if (secpath_has_tunnel(sp, k)) + goto reject; xfrm_pol_put(pol); return 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/security/commoncap.c linux-2.6.9/security/commoncap.c --- linux.vanilla-2.6.9/security/commoncap.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/security/commoncap.c 2004-10-16 22:45:22.000000000 +0100 @@ -127,7 +127,7 @@ if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || !cap_issubset (new_permitted, current->cap_permitted)) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { if (!capable(CAP_SETUID)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/security/dummy.c linux-2.6.9/security/dummy.c --- linux.vanilla-2.6.9/security/dummy.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/security/dummy.c 2004-10-16 22:45:22.000000000 +0100 @@ -174,7 +174,7 @@ static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) { if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) { bprm->e_uid = current->uid; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/security/selinux/hooks.c linux-2.6.9/security/selinux/hooks.c --- linux.vanilla-2.6.9/security/selinux/hooks.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/security/selinux/hooks.c 2004-11-19 23:04:33.000000000 +0000 @@ -637,10 +637,12 @@ case PF_UNIX: switch (type) { case SOCK_STREAM: + case SOCK_SEQPACKET: return SECCLASS_UNIX_STREAM_SOCKET; case SOCK_DGRAM: return SECCLASS_UNIX_DGRAM_SOCKET; } + break; case PF_INET: case PF_INET6: switch (type) { @@ -651,6 +653,7 @@ case SOCK_RAW: return SECCLASS_RAWIP_SOCKET; } + break; case PF_NETLINK: switch (protocol) { case NETLINK_ROUTE: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/security/selinux/ss/avtab.c linux-2.6.9/security/selinux/ss/avtab.c --- linux.vanilla-2.6.9/security/selinux/ss/avtab.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/security/selinux/ss/avtab.c 2004-11-25 21:23:00.000000000 +0000 @@ -407,3 +407,8 @@ sizeof(struct avtab_node), 0, SLAB_PANIC, NULL, NULL); } + +void avtab_cache_destroy(void) +{ + kmem_cache_destroy (avtab_node_cachep); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/security/selinux/ss/avtab.h linux-2.6.9/security/selinux/ss/avtab.h --- linux.vanilla-2.6.9/security/selinux/ss/avtab.h 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/security/selinux/ss/avtab.h 2004-11-25 21:23:00.000000000 +0000 @@ -79,6 +79,7 @@ struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified); void avtab_cache_init(void); +void avtab_cache_destroy(void); #define AVTAB_HASH_BITS 15 #define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/security/selinux/ss/services.c linux-2.6.9/security/selinux/ss/services.c --- linux.vanilla-2.6.9/security/selinux/ss/services.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/security/selinux/ss/services.c 2004-11-25 21:23:00.000000000 +0000 @@ -1037,11 +1037,13 @@ avtab_cache_init(); if (policydb_read(&policydb, fp)) { LOAD_UNLOCK; + avtab_cache_destroy(); return -EINVAL; } if (policydb_load_isids(&policydb, &sidtab)) { LOAD_UNLOCK; policydb_destroy(&policydb); + avtab_cache_destroy(); return -EINVAL; } ss_initialized = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/core/oss/pcm_oss.c linux-2.6.9/sound/core/oss/pcm_oss.c --- linux.vanilla-2.6.9/sound/core/oss/pcm_oss.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/core/oss/pcm_oss.c 2004-11-26 14:14:56.000000000 +0000 @@ -830,13 +830,18 @@ xfer += tmp; if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) || runtime->oss.buffer_used == runtime->oss.period_bytes) { - tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.buffer_used, 1); + tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, + runtime->oss.buffer_used - runtime->oss.period_ptr, 1); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; - runtime->oss.buffer_used = 0; runtime->oss.period_ptr += tmp; runtime->oss.period_ptr %= runtime->oss.period_bytes; + if (runtime->oss.period_ptr == 0 || + runtime->oss.period_ptr == runtime->oss.buffer_used) + runtime->oss.buffer_used = 0; + else if ((substream->ffile->f_flags & O_NONBLOCK) != 0) + return xfer > 0 ? xfer : -EAGAIN; } } else { tmp = snd_pcm_oss_write2(substream, (char *)buf, runtime->oss.period_bytes, 0); @@ -846,6 +851,9 @@ buf += tmp; bytes -= tmp; xfer += tmp; + if ((substream->ffile->f_flags & O_NONBLOCK) != 0 && + tmp != runtime->oss.period_bytes) + break; } } return xfer; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/pci/intel8x0.c linux-2.6.9/sound/pci/intel8x0.c --- linux.vanilla-2.6.9/sound/pci/intel8x0.c 2004-10-20 23:17:36.000000000 +0100 +++ linux-2.6.9/sound/pci/intel8x0.c 2004-11-25 21:39:23.000000000 +0000 @@ -1029,7 +1029,9 @@ */ if (cnt & ICH_PCM_246_MASK) { iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_PCM_246_MASK); + spin_unlock_irq(&chip->reg_lock); msleep(50); /* grrr... */ + spin_lock_irq(&chip->reg_lock); } } else if (chip->device_type == DEVICE_INTEL_ICH4) { if (sample_bits > 16)