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/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/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/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/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/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/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-10-28 00:49:09.000000000 +0100 @@ -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))) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/agp/frontend.c linux-2.6.9/drivers/char/agp/frontend.c --- linux.vanilla-2.6.9/drivers/char/agp/frontend.c 2004-10-20 22:32:27.000000000 +0100 +++ linux-2.6.9/drivers/char/agp/frontend.c 2004-10-16 23:24:44.000000000 +0100 @@ -632,6 +632,7 @@ size, vma->vm_page_prot)) { goto out_again; } + else vma->vm_flags |= VM_IO; up(&(agp_fe.agp_mutex)); return 0; } @@ -648,6 +649,7 @@ size, vma->vm_page_prot)) { goto out_again; } + else vma->vm_flags |= VM_IO; up(&(agp_fe.agp_mutex)); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/char/drm/drm_vm.h linux-2.6.9/drivers/char/drm/drm_vm.h --- linux.vanilla-2.6.9/drivers/char/drm/drm_vm.h 2004-10-20 23:16:49.000000000 +0100 +++ linux-2.6.9/drivers/char/drm/drm_vm.h 2004-10-16 23:22:48.000000000 +0100 @@ -661,6 +661,8 @@ vma->vm_flags |= VM_RESERVED; /* Don't swap */ #endif + vma->vm_flags |= VM_IO; /* IO space so no O_DIRECT etc */ + vma->vm_file = filp; /* Needed for drm_vm_open() */ DRM(vm_open)(vma); return 0; 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/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/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-10-24 17:32:59.000000000 +0100 @@ -205,11 +205,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 +322,90 @@ #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; +} + +/* + * 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 +576,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 +595,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 +611,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 +770,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 +831,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 +850,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 +892,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 +913,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 +958,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 +982,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 +1056,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 +1074,7 @@ hwif->dma_vendor3 = 0; hwif->dma_prdtable = 0; } + hwif->chipset = ide_unknown; /* copy original settings */ tmp_hwif = *hwif; @@ -922,15 +1083,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 @@ -991,7 +1195,8 @@ * @hwifp: pointer to returned hwif * * 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. * * Returns -1 on error. */ @@ -1001,6 +1206,8 @@ 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,28 +1218,37 @@ 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); @@ -1069,21 +1285,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 +1323,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 +1333,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 +1341,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 +1419,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 +1618,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 +1631,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 +1689,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 +1838,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 +1847,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; @@ -2300,6 +2524,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 +2533,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 +2566,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 +2578,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 +2618,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 +2736,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-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-10-17 00:37:01.000000000 +0100 @@ -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. @@ -1184,24 +1188,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 +1221,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 +1244,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 +1617,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-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-10-17 00:38:51.000000000 +0100 @@ -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 */ 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-10-17 00:39:09.000000000 +0100 @@ -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-10-16 22:38:17.000000000 +0100 @@ -740,6 +740,7 @@ 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") && + !strstr(drive->id->model, "Integrated Technology Express") && /* 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) && 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-10-24 17:32:00.000000000 +0100 @@ -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-10-17 01:10:00.000000000 +0100 @@ -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(&hw, hwif); } /*====================================================================== @@ -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/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-10-28 00:08:43.000000000 +0100 @@ -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(&hw, &hwif); + 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-10-17 00:50:18.000000000 +0100 @@ -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,6 +107,11 @@ { 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 1; if (dev->vendor == PCI_VENDOR_ID_UMC && dev->device == PCI_DEVICE_ID_UMC_UM8886A && @@ -108,8 +124,7 @@ return 1; 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; } @@ -117,22 +132,29 @@ 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-10-24 18:04:21.000000000 +0100 @@ -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/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-10-27 15:08:05.000000000 +0100 @@ -0,0 +1,847 @@ +/* + * linux/drivers/ide/pci/it8212.c Version 0.03se October 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. + * + * ** NOTE ** - this is the "special edition" driver for the older IDE + * code. It contains some uglies and has some minor limitations not found + * in the 'new ide' version. As the cleanups enter mainstream IDE so the + * hacks internal to this driver will vanish. + * + * 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 use the same UDMA timing and + * cannot do ATAPI DMA, while the other revisions can do ATAPI UDMA + * but not 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 + * - Rev 0x10 in pass through mode needs UDMA clock whacking + * to work around h/w issues + * - Is rev 0x10 out anywhere - test it if so + * - 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 + + +/** + * 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 - program the PIO/MWDMA 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; + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, 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 */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + 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 */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + 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. + * + * FIXME: for 0x10 model we should reprogram UDMA here + */ + +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]); + 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. + * + * FIXME: for 0x10 model we should reprogram UDMA here + */ + +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_fake_geometry - geometry armwave for raid + * @drive: drive to fake it for + * + * IDE permits a drive to report that it has no geometry. Our + * ide disk layer can't handle this and "functions non-optimally" + * We fake up a geometry here until the ide-disk code patches to + * handle this properly are merged, at which point to goes away + * + * This will always be called for LBA48 assumptions as raid volumes + * are always LBA48 capable. + */ + +static void it8212_fake_geometry(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + unsigned long long capacity = id->lba_capacity_2; + unsigned int cap0 = capacity; /* Trimmed to 32bit */ + unsigned int cyl; + + drive->bios_sect = 63; + drive->bios_head = 255; + + if(cap0 != capacity) + drive->bios_cyl = 65536; + else { + cyl = cap0 / (63 * 255); + if(cyl > 65535) + cyl = 65535; + drive->bios_cyl = cyl; + } + /* We now have a "geometry" to feed back to the ide-disk code */ + id->cyls = drive->bios_cyl; + id->heads = drive->bios_head; + id->sectors = drive->bios_sect; + id->cur_cyls = id->cyls; + id->cur_heads = id->heads; + id->cur_sectors = id->sectors; +} + +/** + * init_iops_it8212 - iops callback + * @hwif: interface + * + * This callback is meant for hwif I/O operation setup. However + * we use it as a hook to patch various things up to avoid explosions + * in the IDE driver core. + */ + +static void __devinit init_iops_it8212(ide_hwif_t *hwif) +{ + int i; + u8 conf; + + /* In IDE mode the controller works fine as is. Remember + hwifdata is not set yet. */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(!(conf & 1)) + return; + + /* Perform fixups */ + + for(i = 0; i < 1; 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 */ + /* Now do fixups needed because of IDE core */ + it8212_fake_geometry(drive); + /* 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"); + } else { + /* Non RAID volume. Fixups to stop the core code + crashing the driver. Go away when ->taskfile hook + is present */ + 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); + + 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: DMA is not currently supported on revision 0x10 in pass through.\n"); + goto fallback; + } + } + + 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_iops = init_iops_it8212, \ + .init_hwif = init_hwif_it8212, \ + .channels = 2, \ + .autodma = AUTODMA, \ + .bootable = ON_BOARD, \ + } + +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_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-10-27 22:39:33.000000000 +0100 @@ -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-10-28 00:31:24.000000000 +0100 @@ -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/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-10-17 00:53:10.000000000 +0100 @@ -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; @@ -762,6 +779,53 @@ 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/ieee1394/dma.c linux-2.6.9/drivers/ieee1394/dma.c --- linux.vanilla-2.6.9/drivers/ieee1394/dma.c 2004-10-20 22:32:50.000000000 +0100 +++ linux-2.6.9/drivers/ieee1394/dma.c 2004-10-16 23:27:08.000000000 +0100 @@ -249,7 +249,7 @@ vma->vm_ops = &dma_region_vm_ops; vma->vm_private_data = dma; vma->vm_file = file; - vma->vm_flags |= VM_RESERVED; + vma->vm_flags |= VM_RESERVED|VM_IO; return 0; } 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/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-10-21 22:43:34.000000000 +0100 @@ -3801,6 +3801,7 @@ pos = (unsigned long)(cam->frame_buf); while (size > 0) { page = kvirt_to_pa(pos); + vma->vm_flags |= VM_IO; if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { up(&cam->busy_lock); return -EAGAIN; @@ -4066,22 +4067,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/meye.c linux-2.6.9/drivers/media/video/meye.c --- linux.vanilla-2.6.9/drivers/media/video/meye.c 2004-10-20 23:16:53.000000000 +0100 +++ linux-2.6.9/drivers/media/video/meye.c 2004-10-16 23:29:16.000000000 +0100 @@ -1202,6 +1202,7 @@ while (size > 0) { page = kvirt_to_pa(pos); + vma->vm_flags |= VM_IO; if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { up(&meye.lock); return -EAGAIN; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/media/video/planb.c linux-2.6.9/drivers/media/video/planb.c --- linux.vanilla-2.6.9/drivers/media/video/planb.c 2004-10-20 22:32:30.000000000 +0100 +++ linux-2.6.9/drivers/media/video/planb.c 2004-10-16 23:30:55.000000000 +0100 @@ -1995,6 +1995,7 @@ if((err=grabbuf_alloc(pb))) return err; } + vma->vm_flags |= VM_IO; for (i = 0; i < pb->rawbuf_size; i++) { if (remap_page_range(vma, start, virt_to_phys((void *)pb->rawbuf[i]), PAGE_SIZE, PAGE_SHARED)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/media/video/zoran_driver.c linux-2.6.9/drivers/media/video/zoran_driver.c --- linux.vanilla-2.6.9/drivers/media/video/zoran_driver.c 2004-10-20 23:16:54.000000000 +0100 +++ linux-2.6.9/drivers/media/video/zoran_driver.c 2004-10-16 23:29:56.000000000 +0100 @@ -4556,6 +4556,7 @@ (unsigned long) fh->jpg_buffers. buffer[i].frag_tab[2 * j]; page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ + vma->vm_flags |= VM_IO; if (zr_remap_page_range (vma, start, page, todo, PAGE_SHARED)) { dprintk(1, 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-10-16 23:30:27.000000000 +0100 @@ -1472,9 +1472,11 @@ if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) return -EINVAL; + vma->vm_flags |= VM_IO; + /* 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/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/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_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/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/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-10-24 17:37:01.000000000 +0100 @@ -5090,7 +5090,6 @@ ahd_linux_exit(void) { struct ahd_softc *ahd; - u_long l; /* * Shutdown DV threads before going into the SCSI mid-layer. @@ -5098,12 +5097,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/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/usb/class/audio.c linux-2.6.9/drivers/usb/class/audio.c --- linux.vanilla-2.6.9/drivers/usb/class/audio.c 2004-10-20 23:16:56.000000000 +0100 +++ linux-2.6.9/drivers/usb/class/audio.c 2004-10-16 23:35:29.000000000 +0100 @@ -508,6 +508,7 @@ if (!db->sgbuf[nr]) return -EINVAL; db->mapped = 1; + vma->vm_flags |= VM_IO; for(nr = 0; nr < size; nr++) { if (remap_page_range(vma, start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot)) return -EAGAIN; 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-10-21 00:07:14.000000000 +0100 @@ -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-10-21 00:07:14.000000000 +0100 @@ -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/ov511.c linux-2.6.9/drivers/usb/media/ov511.c --- linux.vanilla-2.6.9/drivers/usb/media/ov511.c 2004-10-20 23:16:57.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/ov511.c 2004-10-16 23:35:52.000000000 +0100 @@ -4769,6 +4769,7 @@ if (down_interruptible(&ov->lock)) return -EINTR; + vma->vm_flags |= VM_IO; pos = (unsigned long)ov->fbuf; while (size > 0) { page = kvirt_to_pa(pos); 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-10-21 00:07:14.000000000 +0100 @@ -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/media/se401.c linux-2.6.9/drivers/usb/media/se401.c --- linux.vanilla-2.6.9/drivers/usb/media/se401.c 2004-10-20 23:16:58.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/se401.c 2004-10-16 23:36:08.000000000 +0100 @@ -1180,6 +1180,7 @@ up(&se401->lock); return -EINVAL; } + vma->vm_flags |= VM_IO; pos = (unsigned long)se401->fbuf; while (size > 0) { page = kvirt_to_pa(pos); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/sn9c102_core.c linux-2.6.9/drivers/usb/media/sn9c102_core.c --- linux.vanilla-2.6.9/drivers/usb/media/sn9c102_core.c 2004-10-20 23:16:58.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/sn9c102_core.c 2004-10-16 23:36:50.000000000 +0100 @@ -1497,6 +1497,7 @@ return -EINVAL; } + vma->vm_flags |= VM_IO; pos = (unsigned long)cam->frame[i].bufmem; while (size > 0) { /* size is page-aligned */ page = kvirt_to_pa(pos); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/stv680.c linux-2.6.9/drivers/usb/media/stv680.c --- linux.vanilla-2.6.9/drivers/usb/media/stv680.c 2004-10-20 23:16:58.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/stv680.c 2004-10-16 23:37:10.000000000 +0100 @@ -1289,6 +1289,7 @@ up (&stv680->lock); return -EINVAL; } + vma->vm_flags |= VM_IO; pos = (unsigned long) stv680->fbuf; while (size > 0) { page = kvirt_to_pa (pos); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/usbvideo.c linux-2.6.9/drivers/usb/media/usbvideo.c --- linux.vanilla-2.6.9/drivers/usb/media/usbvideo.c 2004-10-20 23:16:58.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/usbvideo.c 2004-10-16 23:37:32.000000000 +0100 @@ -1166,6 +1166,7 @@ if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; + vma->vm_flags |= VM_IO; pos = (unsigned long) uvd->fbuf; while (size > 0) { page = usbvideo_kvirt_to_pa(pos); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/vicam.c linux-2.6.9/drivers/usb/media/vicam.c --- linux.vanilla-2.6.9/drivers/usb/media/vicam.c 2004-10-20 22:33:06.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/vicam.c 2004-10-16 23:38:02.000000000 +0100 @@ -1052,6 +1052,8 @@ if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) return -EINVAL; */ + + vma->vm_flags |= VM_IO; pos = (unsigned long)cam->framebuf; while (size > 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/drivers/usb/media/w9968cf.c linux-2.6.9/drivers/usb/media/w9968cf.c --- linux.vanilla-2.6.9/drivers/usb/media/w9968cf.c 2004-10-20 22:33:06.000000000 +0100 +++ linux-2.6.9/drivers/usb/media/w9968cf.c 2004-10-16 23:38:28.000000000 +0100 @@ -2918,6 +2918,8 @@ if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) return -EINVAL; + vma->vm_flags |= VM_IO; + while (vsize > 0) { page = kvirt_to_pa(pos) + vma->vm_pgoff; if (remap_page_range(vma, start, page, PAGE_SIZE, 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-10-24 17:26:59.000000000 +0100 @@ -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,32 @@ 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; + } + ++priv->outstanding_urbs; + spin_unlock_irqrestore(&priv->lock, flags); + buffer = kmalloc (count, GFP_ATOMIC); if (!buffer) { dev_err(&port->dev, "out of memory\n"); @@ -514,7 +539,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 +583,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 +595,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 +606,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 +634,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 +871,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 +926,7 @@ return -EIO; } - return 0; + return generic_startup(serial); } static int treo_attach (struct usb_serial *serial) @@ -911,7 +965,7 @@ COPY_PORT(serial->port[1], swap_port); kfree(swap_port); - return 0; + 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/video/controlfb.c linux-2.6.9/drivers/video/controlfb.c --- linux.vanilla-2.6.9/drivers/video/controlfb.c 2004-10-20 23:17:05.000000000 +0100 +++ linux-2.6.9/drivers/video/controlfb.c 2004-10-16 23:39:59.000000000 +0100 @@ -314,6 +314,7 @@ if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; + vma->vm_flags |= VM_IO; vma->vm_pgoff = off >> PAGE_SHIFT; if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) 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-10-21 19:39:41.000000000 +0100 @@ -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; @@ -845,6 +849,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 +868,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 */ @@ -1378,7 +1385,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 +1396,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 +1423,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 +1447,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-28 00:18:51.000000000 +0100 @@ -999,11 +999,12 @@ error = first; goto out_fail; } - if (FAT_FIRST_ENT(sb, media) == first) { - /* all is as it should be */ - } else if (media == 0xf8 && FAT_FIRST_ENT(sb, 0xfe) == first) { + + if ((FAT_FIRST_ENT(sb, media) | 0x03) == first) { + /* all is as it should be: -1 to -8 */ + } else if (media == 0xf8 && (FAT_FIRST_ENT(sb, 0xfe) | 0x03) == first) { /* bad, reported on pc9800 */ - } else if (media == 0xf0 && FAT_FIRST_ENT(sb, 0xf8) == first) { + } else if (media == 0xf0 && (FAT_FIRST_ENT(sb, 0xf8) | 0x03) == first) { /* bad, reported with a MO disk on win95/me */ } else if (first == 0) { /* bad, reported with a SmartMedia card */ 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-10-16 22:21:08.000000000 +0100 @@ -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; @@ -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/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-10-21 22:25:45.000000000 +0100 @@ -634,6 +634,7 @@ 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; @@ -657,8 +658,11 @@ * 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: 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-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-10-28 00:40:34.000000000 +0100 @@ -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/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-10-16 22:13:30.000000000 +0100 @@ -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/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-10-21 15:36:07.000000000 +0100 @@ -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/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-10-24 17:32:59.000000000 +0100 @@ -815,6 +815,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 +823,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 +881,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 +951,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 */ @@ -1047,6 +1055,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 +1076,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 *); @@ -1419,6 +1433,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 +1485,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); @@ -1570,8 +1587,9 @@ #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 int probe_hwif_init(ide_hwif_t *); 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/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-10-28 00:42:29.000000000 +0100 @@ -1199,6 +1199,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 +1258,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 +1648,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 +2331,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/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-10-16 22:44:36.000000000 +0100 @@ -230,7 +230,7 @@ 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/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/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/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-10-24 18:58:59.000000000 +0100 @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 9 -EXTRAVERSION = -NAME=Zonked Quokka +EXTRAVERSION = -ac5 +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/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/packet/af_packet.c linux-2.6.9/net/packet/af_packet.c --- linux.vanilla-2.6.9/net/packet/af_packet.c 2004-10-20 23:17:34.000000000 +0100 +++ linux-2.6.9/net/packet/af_packet.c 2004-10-16 23:46:27.000000000 +0100 @@ -1727,6 +1727,7 @@ atomic_inc(&po->mapped); start = vma->vm_start; + vma->vm_flags |= VM_IO; err = -EAGAIN; for (i=0; ipg_vec_len; i++) { if (remap_page_range(vma, start, __pa(po->pg_vec[i]), 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/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/sound/oss/ali5455.c linux-2.6.9/sound/oss/ali5455.c --- linux.vanilla-2.6.9/sound/oss/ali5455.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/ali5455.c 2004-10-16 23:49:56.000000000 +0100 @@ -1954,6 +1954,8 @@ size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << dmabuf->buforder)) goto out; + + vma->vm_flags |= VM_IO; ret = -EAGAIN; if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/au1000.c linux-2.6.9/sound/oss/au1000.c --- linux.vanilla-2.6.9/sound/oss/au1000.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/au1000.c 2004-10-16 23:50:18.000000000 +0100 @@ -1338,6 +1338,7 @@ ret = -EINVAL; goto out; } + vma->vm_flags |= VM_IO; if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { ret = -EAGAIN; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/cmpci.c linux-2.6.9/sound/oss/cmpci.c --- linux.vanilla-2.6.9/sound/oss/cmpci.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/cmpci.c 2004-10-16 23:50:38.000000000 +0100 @@ -2301,6 +2301,7 @@ if (size > (PAGE_SIZE << db->buforder)) goto out; ret = -EINVAL; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) goto out; db->mapped = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/cs4281/cs4281m.c linux-2.6.9/sound/oss/cs4281/cs4281m.c --- linux.vanilla-2.6.9/sound/oss/cs4281/cs4281m.c 2004-10-20 22:33:16.000000000 +0100 +++ linux-2.6.9/sound/oss/cs4281/cs4281m.c 2004-10-16 23:52:41.000000000 +0100 @@ -3135,6 +3135,7 @@ size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) return -EINVAL; + vma->vm_flags |= VM_IO; if (remap_page_range (vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/cs46xx.c linux-2.6.9/sound/oss/cs46xx.c --- linux.vanilla-2.6.9/sound/oss/cs46xx.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/cs46xx.c 2004-10-16 23:51:13.000000000 +0100 @@ -2452,6 +2452,7 @@ ret = -EINVAL; goto out; } + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/es1370.c linux-2.6.9/sound/oss/es1370.c --- linux.vanilla-2.6.9/sound/oss/es1370.c 2004-10-20 22:33:15.000000000 +0100 +++ linux-2.6.9/sound/oss/es1370.c 2004-10-16 23:51:36.000000000 +0100 @@ -1364,6 +1364,7 @@ ret = -EINVAL; goto out; } + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { ret = -EAGAIN; goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/es1371.c linux-2.6.9/sound/oss/es1371.c --- linux.vanilla-2.6.9/sound/oss/es1371.c 2004-10-20 22:33:14.000000000 +0100 +++ linux-2.6.9/sound/oss/es1371.c 2004-10-16 23:52:03.000000000 +0100 @@ -1555,6 +1555,7 @@ ret = -EINVAL; goto out; } + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { ret = -EAGAIN; goto out; @@ -2128,6 +2129,7 @@ if (size > (PAGE_SIZE << s->dma_dac1.buforder)) goto out; ret = -EAGAIN; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot)) goto out; s->dma_dac1.mapped = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/esssolo1.c linux-2.6.9/sound/oss/esssolo1.c --- linux.vanilla-2.6.9/sound/oss/esssolo1.c 2004-10-20 22:33:15.000000000 +0100 +++ linux-2.6.9/sound/oss/esssolo1.c 2004-10-16 23:53:07.000000000 +0100 @@ -1242,6 +1242,7 @@ if (size > (PAGE_SIZE << db->buforder)) goto out; ret = -EAGAIN; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) goto out; db->mapped = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/i810_audio.c linux-2.6.9/sound/oss/i810_audio.c --- linux.vanilla-2.6.9/sound/oss/i810_audio.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/i810_audio.c 2004-10-16 23:53:33.000000000 +0100 @@ -1750,6 +1750,7 @@ if (size > (PAGE_SIZE << dmabuf->buforder)) goto out; ret = -EAGAIN; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/ite8172.c linux-2.6.9/sound/oss/ite8172.c --- linux.vanilla-2.6.9/sound/oss/ite8172.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/ite8172.c 2004-10-16 23:53:53.000000000 +0100 @@ -1311,6 +1311,7 @@ unlock_kernel(); return -EINVAL; } + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { unlock_kernel(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/maestro3.c linux-2.6.9/sound/oss/maestro3.c --- linux.vanilla-2.6.9/sound/oss/maestro3.c 2004-10-20 22:33:14.000000000 +0100 +++ linux-2.6.9/sound/oss/maestro3.c 2004-10-16 23:54:13.000000000 +0100 @@ -1557,6 +1557,7 @@ * ask Jeff what the hell I'm doing wrong. */ ret = -EAGAIN; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/maestro.c linux-2.6.9/sound/oss/maestro.c --- linux.vanilla-2.6.9/sound/oss/maestro.c 2004-10-20 22:33:14.000000000 +0100 +++ linux-2.6.9/sound/oss/maestro.c 2004-10-16 23:54:41.000000000 +0100 @@ -2520,6 +2520,7 @@ if (size > (PAGE_SIZE << db->buforder)) goto out; ret = -EAGAIN; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) goto out; db->mapped = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/rme96xx.c linux-2.6.9/sound/oss/rme96xx.c --- linux.vanilla-2.6.9/sound/oss/rme96xx.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/rme96xx.c 2004-10-16 23:55:24.000000000 +0100 @@ -1681,7 +1681,6 @@ return -EINVAL; } - if (vma->vm_flags & VM_WRITE) { if (!s->started) rme96xx_startcard(s,1); @@ -1689,6 +1688,7 @@ unlock_kernel(); return -EAGAIN; } + vma->vm_flags |= VM_IO; } else if (vma->vm_flags & VM_READ) { if (!s->started) rme96xx_startcard(s,1); @@ -1696,6 +1696,7 @@ unlock_kernel(); return -EAGAIN; } + vma->vm_flags |= VM_IO; } else { unlock_kernel(); return -EINVAL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/sonicvibes.c linux-2.6.9/sound/oss/sonicvibes.c --- linux.vanilla-2.6.9/sound/oss/sonicvibes.c 2004-10-20 22:33:15.000000000 +0100 +++ linux-2.6.9/sound/oss/sonicvibes.c 2004-10-16 23:55:43.000000000 +0100 @@ -1549,6 +1549,7 @@ if (size > (PAGE_SIZE << db->buforder)) goto out; ret = -EAGAIN; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) goto out; db->mapped = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/trident.c linux-2.6.9/sound/oss/trident.c --- linux.vanilla-2.6.9/sound/oss/trident.c 2004-10-20 23:17:35.000000000 +0100 +++ linux-2.6.9/sound/oss/trident.c 2004-10-16 23:56:02.000000000 +0100 @@ -2223,6 +2223,7 @@ if (size > (PAGE_SIZE << dmabuf->buforder)) goto out; ret = -EAGAIN; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.9/sound/oss/ymfpci.c linux-2.6.9/sound/oss/ymfpci.c --- linux.vanilla-2.6.9/sound/oss/ymfpci.c 2004-10-20 22:33:14.000000000 +0100 +++ linux-2.6.9/sound/oss/ymfpci.c 2004-10-16 23:56:25.000000000 +0100 @@ -1545,6 +1545,7 @@ size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << dmabuf->buforder)) return -EINVAL; + vma->vm_flags |= VM_IO; if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) return -EAGAIN;