diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/i386/boot/edd.S linux-2.6.10/arch/i386/boot/edd.S --- linux.vanilla-2.6.10/arch/i386/boot/edd.S 2004-12-25 21:14:53.000000000 +0000 +++ linux-2.6.10/arch/i386/boot/edd.S 2004-12-26 17:32:19.000000000 +0000 @@ -1,5 +1,6 @@ /* * BIOS Enhanced Disk Drive support + * Copyright (C) 2002, 2003, 2004 Dell, Inc. * by Matt Domsch October 2002 * conformant to T13 Committee www.t13.org * projects 1572D, 1484D, 1386D, 1226DT @@ -7,14 +8,52 @@ * and Andrew Wilks September 2003, June 2004 * legacy CHS retreival by Patrick J. LoPresti * March 2004 + * Command line option parsing, Matt Domsch, November 2004 */ #include +#include #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) + movb $0, (EDD_MBR_SIG_NR_BUF) # zero value at EDD_MBR_SIG_NR_BUF + movb $0, (EDDNR) # zero value at EDDNR + +# Check the command line for two options: +# edd=of disables EDD completely (edd=off) +# edd=sk skips the MBR test (edd=skipmbr) + pushl %esi + cmpl $0, %cs:cmd_line_ptr + jz done_cl + movl %cs:(cmd_line_ptr), %esi +# ds:esi has the pointer to the command line now + movl $(COMMAND_LINE_SIZE-6), %ecx +# loop through kernel command line one byte at a time +cl_loop: + cmpl $EDD_CL_EQUALS, (%si) + jz found_edd_equals + incl %esi + loop cl_loop + jmp done_cl +found_edd_equals: +# only looking at first two characters after equals + addl $4, %esi + cmpw $EDD_CL_OFF, (%si) # edd=of + jz do_edd_off + cmpw $EDD_CL_SKIP, (%si) # edd=sk + jz do_edd_skipmbr + jmp done_cl +do_edd_skipmbr: + popl %esi + jmp edd_start +do_edd_off: + popl %esi + jmp edd_done +done_cl: + popl %esi + + # Read the first sector of each BIOS disk device and store the 4-byte signature edd_mbr_sig_start: - movb $0, (EDD_MBR_SIG_NR_BUF) # zero value at EDD_MBR_SIG_NR_BUF movb $0x80, %dl # from device 80 movw $EDD_MBR_SIG_BUF, %bx # store buffer ptr in bx edd_mbr_sig_read: @@ -76,7 +115,6 @@ # result buffer for fn48 movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results # kept just before that - movb $0, (EDDNR) # zero value at EDDNR movb $0x80, %dl # BIOS device 0x80 edd_check_ext: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/i386/Kconfig linux-2.6.10/arch/i386/Kconfig --- linux.vanilla-2.6.10/arch/i386/Kconfig 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/i386/Kconfig 2004-12-26 17:31:57.000000000 +0000 @@ -330,6 +330,14 @@ endchoice +config X86_HZ + int "Clock Tick Rate" + default 1000 if !(M386 || M486 || M586 || M586TSC || M586MMX) + default 100 if (M386 || M486 || M586 || M586TSC || M586MMX) + help + Select the kernel clock tick rate in interrupts per second. + Slower processors should choose 100; everything else 1000. + config X86_GENERIC bool "Generic x86 support" help diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/i386/kernel/apic.c linux-2.6.10/arch/i386/kernel/apic.c --- linux.vanilla-2.6.10/arch/i386/kernel/apic.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/i386/kernel/apic.c 2005-01-03 19:02:40.000000000 +0000 @@ -519,7 +519,7 @@ * Otherwise the BIOS may get confused and not power-off. */ void -lapic_shutdown() +lapic_shutdown(void) { if (!cpu_has_apic || !enabled_via_apicbase) return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/i386/kernel/Makefile linux-2.6.10/arch/i386/kernel/Makefile --- linux.vanilla-2.6.10/arch/i386/kernel/Makefile 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/i386/kernel/Makefile 2004-12-26 17:30:59.000000000 +0000 @@ -33,7 +33,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -EXTRA_AFLAGS := -traditional +EXTRA_AFLAGS := -traditional -m32 obj-$(CONFIG_SCx200) += scx200.o @@ -51,7 +51,7 @@ export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH) -vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 +vsyscall-flags = -m32 -shared -s -Wl,-soname=linux-gate.so.1 SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) @@ -66,6 +66,6 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o -SYSCFLAGS_vsyscall-syms.o = -r +SYSCFLAGS_vsyscall-syms.o = -m32 -r $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE $(call if_changed,syscall) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/i386/kernel/microcode.c linux-2.6.10/arch/i386/kernel/microcode.c --- linux.vanilla-2.6.10/arch/i386/kernel/microcode.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/i386/kernel/microcode.c 2004-12-26 17:30:43.000000000 +0000 @@ -364,7 +364,7 @@ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; if (uci->mc == NULL) { - printk(KERN_INFO "microcode: No suitable data for CPU%d\n", cpu_num); + printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/i386/pci/irq.c linux-2.6.10/arch/i386/pci/irq.c --- linux.vanilla-2.6.10/arch/i386/pci/irq.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/i386/pci/irq.c 2005-01-03 18:26:02.000000000 +0000 @@ -491,6 +491,8 @@ case PCI_DEVICE_ID_INTEL_ESB_1: case PCI_DEVICE_ID_INTEL_ICH6_0: case PCI_DEVICE_ID_INTEL_ICH6_1: + case PCI_DEVICE_ID_INTEL_ICH7_0: + case PCI_DEVICE_ID_INTEL_ICH7_1: r->name = "PIIX/ICH"; r->get = pirq_piix_get; r->set = pirq_piix_set; @@ -1022,7 +1024,7 @@ int pirq_enable_irq(struct pci_dev *dev) { u8 pin; - extern int interrupt_line_quirk; + extern int via_interrupt_line_quirk; struct pci_dev *temp_dev; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); @@ -1080,7 +1082,7 @@ } /* VIA bridges use interrupt line for apic/pci steering across the V-Link */ - else if (interrupt_line_quirk) + else if (via_interrupt_line_quirk) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/ia64/kernel/sys_ia64.c linux-2.6.10/arch/ia64/kernel/sys_ia64.c --- linux.vanilla-2.6.10/arch/ia64/kernel/sys_ia64.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/ia64/kernel/sys_ia64.c 2005-01-07 15:36:22.000000000 +0000 @@ -147,7 +147,7 @@ goto out; /* Ok, looks good - let it rip. */ - if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) + if (__do_brk(oldbrk, newbrk-oldbrk) != oldbrk) goto out; set_brk: mm->brk = brk; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/mips/kernel/sysirix.c linux-2.6.10/arch/mips/kernel/sysirix.c --- linux.vanilla-2.6.10/arch/mips/kernel/sysirix.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/mips/kernel/sysirix.c 2005-01-07 15:36:33.000000000 +0000 @@ -591,7 +591,7 @@ * Ok, looks good - let it rip. */ mm->brk = brk; - do_brk(oldbrk, newbrk-oldbrk); + __do_brk(oldbrk, newbrk-oldbrk); ret = 0; out: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/ppc64/kernel/irq.c linux-2.6.10/arch/ppc64/kernel/irq.c --- linux.vanilla-2.6.10/arch/ppc64/kernel/irq.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/ppc64/kernel/irq.c 2005-01-04 17:27:45.000000000 +0000 @@ -213,7 +213,7 @@ spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); 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.10/arch/sparc/kernel/sys_sunos.c linux-2.6.10/arch/sparc/kernel/sys_sunos.c --- linux.vanilla-2.6.10/arch/sparc/kernel/sys_sunos.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/sparc/kernel/sys_sunos.c 2005-01-07 15:37:03.000000000 +0000 @@ -207,7 +207,7 @@ * Ok, we have probably got enough memory - let it rip. */ current->mm->brk = brk; - do_brk(oldbrk, newbrk-oldbrk); + __do_brk(oldbrk, newbrk-oldbrk); retval = 0; out: up_write(¤t->mm->mmap_sem); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/arch/sparc64/kernel/sys_sunos32.c linux-2.6.10/arch/sparc64/kernel/sys_sunos32.c --- linux.vanilla-2.6.10/arch/sparc64/kernel/sys_sunos32.c 2004-12-25 21:15:32.000000000 +0000 +++ linux-2.6.10/arch/sparc64/kernel/sys_sunos32.c 2005-01-07 15:37:23.000000000 +0000 @@ -164,7 +164,7 @@ goto out; /* Ok, we have probably got enough memory - let it rip. */ current->mm->brk = brk; - do_brk(oldbrk, newbrk-oldbrk); + __do_brk(oldbrk, newbrk-oldbrk); retval = 0; out: up_write(¤t->mm->mmap_sem); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/CREDITS linux-2.6.10/CREDITS --- linux.vanilla-2.6.10/CREDITS 2004-12-25 21:15:31.000000000 +0000 +++ linux-2.6.10/CREDITS 2004-12-26 17:29:07.000000000 +0000 @@ -1893,7 +1893,7 @@ D: Bug fixes N: Paul Laufer -E: pelaufer@csupomona.edu +E: paul@laufernet.com D: Soundblaster driver fixes, ISAPnP quirk S: California, USA diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/Documentation/kernel-parameters.txt linux-2.6.10/Documentation/kernel-parameters.txt --- linux.vanilla-2.6.10/Documentation/kernel-parameters.txt 2004-12-25 21:15:31.000000000 +0000 +++ linux-2.6.10/Documentation/kernel-parameters.txt 2005-01-04 17:35:42.000000000 +0000 @@ -29,6 +29,7 @@ CD Appropriate CD support is enabled. DEVFS devfs support is enabled. DRM Direct Rendering Management support is enabled. + EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled EIDE EIDE/ATAPI support is enabled. FB The frame buffer device is enabled. @@ -408,6 +409,10 @@ edb= [HW,PS2] + edd [EDD] + Format: {"of[f]" | "sk[ipmbr]"} + See comment in arch/i386/boot/edd.S + eicon= [HW,ISDN] Format: ,, @@ -569,6 +574,17 @@ ips= [HW,SCSI] Adaptec / IBM ServeRAID controller See header of drivers/scsi/ips.c. + irqfixup [HW] + When an interrupt is not handled search all handlers + for it. Intended to get systems with badly broken + firmware running. + + irqpoll [HW] + When an interrupt is not handled search all handlers + for it. Also check all handlers each timer + interrupt. Intended to get systems with badly broken + firmware running. + isapnp= [ISAPNP] Format: , , , diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/Documentation/sysctl/kernel.txt linux-2.6.10/Documentation/sysctl/kernel.txt --- linux.vanilla-2.6.10/Documentation/sysctl/kernel.txt 2004-12-25 21:14:07.000000000 +0000 +++ linux-2.6.10/Documentation/sysctl/kernel.txt 2004-12-26 18:47:27.000000000 +0000 @@ -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.10/drivers/acpi/ibm_acpi.c linux-2.6.10/drivers/acpi/ibm_acpi.c --- linux.vanilla-2.6.10/drivers/acpi/ibm_acpi.c 2004-12-25 21:15:33.000000000 +0000 +++ linux-2.6.10/drivers/acpi/ibm_acpi.c 2005-01-04 17:37:19.000000000 +0000 @@ -1168,7 +1168,7 @@ #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) -static void __exit acpi_ibm_exit(void) +static void acpi_ibm_exit(void) { int i; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/acpi/pci_irq.c linux-2.6.10/drivers/acpi/pci_irq.c --- linux.vanilla-2.6.10/drivers/acpi/pci_irq.c 2004-12-25 21:15:33.000000000 +0000 +++ linux-2.6.10/drivers/acpi/pci_irq.c 2004-12-29 22:46:48.000000000 +0000 @@ -345,6 +345,7 @@ u8 pin = 0; int edge_level = ACPI_LEVEL_SENSITIVE; int active_high_low = ACPI_ACTIVE_LOW; + extern int via_interrupt_line_quirk; ACPI_FUNCTION_TRACE("acpi_pci_irq_enable"); @@ -394,6 +395,9 @@ } } + if (via_interrupt_line_quirk) + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq & 15); + dev->irq = acpi_register_gsi(irq, edge_level, active_high_low); printk(KERN_INFO PREFIX "PCI interrupt %s[%c] -> GSI %u " diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/block/scsi_ioctl.c linux-2.6.10/drivers/block/scsi_ioctl.c --- linux.vanilla-2.6.10/drivers/block/scsi_ioctl.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/block/scsi_ioctl.c 2004-12-26 17:27:50.000000000 +0000 @@ -356,7 +356,7 @@ bytes = max(in_len, out_len); if (bytes) { - buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER); + buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN); if (!buffer) return -ENOMEM; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/block/sx8.c linux-2.6.10/drivers/block/sx8.c --- linux.vanilla-2.6.10/drivers/block/sx8.c 2004-12-25 21:14:31.000000000 +0000 +++ linux-2.6.10/drivers/block/sx8.c 2004-12-26 17:27:05.000000000 +0000 @@ -1503,7 +1503,7 @@ } port->disk = disk; - sprintf(disk->disk_name, DRV_NAME "%u_%u", host->id, i); + sprintf(disk->disk_name, DRV_NAME "/%u", (host->id * CARM_MAX_PORTS) + i); sprintf(disk->devfs_name, DRV_NAME "/%u_%u", host->id, i); disk->major = host->major; disk->first_minor = i * CARM_MINORS_PER_MAJOR; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/cdrom/cdrom.c linux-2.6.10/drivers/cdrom/cdrom.c --- linux.vanilla-2.6.10/drivers/cdrom/cdrom.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/cdrom/cdrom.c 2005-01-06 21:57:14.000000000 +0000 @@ -1076,6 +1076,8 @@ } cdinfo(CD_OPEN, "the tray is now closed.\n"); } + /* the door should be closed now, check for the disc */ + ret = cdo->drive_status(cdi, CDSL_CURRENT); if (ret!=CDS_DISC_OK) { ret = -ENOMEDIUM; goto clean_up_and_return; @@ -1129,7 +1131,8 @@ This ensures that the drive gets unlocked after a mount fails. This is a goto to avoid bloating the driver with redundant code. */ clean_up_and_return: - cdinfo(CD_WARNING, "open failed.\n"); + /* Don't log this, its a perfectly normal user occurence */ + /* cdinfo(CD_WARNING, "open failed.\n"); */ if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 0); cdinfo(CD_OPEN, "door unlocked.\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/agp.h linux-2.6.10/drivers/char/agp/agp.h --- linux.vanilla-2.6.10/drivers/char/agp/agp.h 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/agp.h 2005-01-03 18:40:21.000000000 +0000 @@ -141,16 +141,6 @@ char minor_version; }; -#define OUTREG64(mmap, addr, val) __raw_writeq((val), (mmap)+(addr)) -#define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) -#define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr)) -#define OUTREG8(mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) - -#define INREG64(mmap, addr) __raw_readq((mmap)+(addr)) -#define INREG32(mmap, addr) __raw_readl((mmap)+(addr)) -#define INREG16(mmap, addr) __raw_readw((mmap)+(addr)) -#define INREG8(mmap, addr) __raw_readb((mmap)+(addr)) - #define KB(x) ((x) * 1024) #define MB(x) (KB (KB (x))) #define GB(x) (MB (KB (x))) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/ali-agp.c linux-2.6.10/drivers/char/agp/ali-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/ali-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/ali-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -277,6 +277,23 @@ .device_id = PCI_DEVICE_ID_AL_M1671, .chipset_name = "M1671", }, + { + .device_id = PCI_DEVICE_ID_AL_M1681, + .chipset_name = "M1681", + }, + { + .device_id = PCI_DEVICE_ID_AL_M1683, + .chipset_name = "M1683", + }, + { + .device_id = PCI_DEVICE_ID_AL_M1681, + .chipset_name = "M1681", + }, + { + .device_id = PCI_DEVICE_ID_AL_M1683, + .chipset_name = "M1683", + }, + { }, /* dummy final entry, always present */ }; @@ -387,6 +404,8 @@ static int __init agp_ali_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_ali_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/alpha-agp.c linux-2.6.10/drivers/char/agp/alpha-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/alpha-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/alpha-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -195,6 +195,8 @@ static int __init agp_alpha_core_init(void) { + if (agp_off) + return -EINVAL; if (alpha_mv.agp_info) return alpha_core_agp_setup(); return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/amd64-agp.c linux-2.6.10/drivers/char/agp/amd64-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/amd64-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/amd64-agp.c 2005-01-03 18:42:22.000000000 +0000 @@ -46,6 +46,11 @@ #define NVIDIA_X86_64_1_APBASE2 0xd8 #define NVIDIA_X86_64_1_APLIMIT2 0xdc +/* ULi K8 registers */ +#define ULI_X86_64_BASE_ADDR 0x10 +#define ULI_X86_64_HTT_FEA_REG 0x50 +#define ULI_X86_64_ENU_SCR_REG 0x54 + static int nr_garts; static struct pci_dev * hammers[MAX_HAMMER_GARTS]; @@ -109,6 +114,7 @@ pte |= GPTE_VALID | GPTE_COHERENT; writel(pte, agp_bridge->gatt_table+j); + readl(agp_bridge->gatt_table+j); /* PCI Posting. */ } amd64_tlbflush(mem); return 0; @@ -355,7 +361,7 @@ int i = 0; /* cache pci_devs of northbridges. */ - while ((loop_dev = pci_find_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) + while ((loop_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) != NULL) { if (i == MAX_HAMMER_GARTS) { printk(KERN_ERR PFX "Too many northbridges for AGP\n"); @@ -405,6 +411,62 @@ } } + +static struct aper_size_info_32 uli_sizes[7] = +{ + {256, 65536, 6, 10}, + {128, 32768, 5, 9}, + {64, 16384, 4, 8}, + {32, 8192, 3, 7}, + {16, 4096, 2, 6}, + {8, 2048, 1, 4}, + {4, 1024, 0, 3} +}; + +static int __devinit uli_agp_init(struct pci_dev *pdev) +{ + u32 httfea,baseaddr,enuscr; + struct pci_dev *dev1; + int i; + unsigned size = amd64_fetch_size(); + printk(KERN_INFO PFX "Setting up ULi AGP. \n"); + dev1 = pci_find_slot ((unsigned int)pdev->bus->number,PCI_DEVFN(0,0)); + if (dev1 == NULL) { + printk(KERN_INFO PFX "agpgart: Detected a ULi chipset, " + "but could not fine the secondary device.\n"); + return -ENODEV; + } + for (i = 0; i < ARRAY_SIZE(uli_sizes); i++) + if (uli_sizes[i].size == size) + break; + + if (i == ARRAY_SIZE(uli_sizes)) { + printk(KERN_INFO PFX "No ULi size found for %d\n", size); + return -ENODEV; + } + + + /* shadow x86-64 registers into ULi registers */ + pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &httfea); + + /* if x86-64 aperture base is beyond 4G, exit here */ + if ( (httfea & 0x7fff) >> (32 - 25) ) + return -ENODEV; + + httfea = (httfea& 0x7fff) << 25; + + pci_read_config_dword(pdev, ULI_X86_64_BASE_ADDR, &baseaddr); + baseaddr&= ~PCI_BASE_ADDRESS_MEM_MASK; + baseaddr|= httfea; + pci_write_config_dword(pdev, ULI_X86_64_BASE_ADDR, baseaddr); + + enuscr= httfea+ (size * 1024 * 1024) - 1; + pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea); + pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr); + return 0; +} + + static struct aper_size_info_32 nforce3_sizes[5] = { {512, 131072, 7, 0x00000000 }, @@ -513,6 +575,14 @@ } } + if (pdev->vendor == PCI_VENDOR_ID_AL) { + int ret = uli_agp_init(pdev); + if (ret) { + agp_put_bridge(bridge); + return ret; + } + } + pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); } @@ -536,6 +606,15 @@ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + /* ULi M1689 */ + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_AL, + .device = PCI_DEVICE_ID_AL_M1689, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, /* VIA K8T800Pro */ { .class = (PCI_CLASS_BRIDGE_HOST << 8), @@ -625,6 +704,11 @@ int __init agp_amd64_init(void) { int err = 0; + static struct pci_device_id amd64nb[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) }, + { }, + }; + if (agp_off) return -EINVAL; if (pci_module_init(&agp_amd64_pci_driver) > 0) { @@ -640,13 +724,13 @@ } /* First check that we have at least one AMD64 NB */ - if (!pci_find_device(PCI_VENDOR_ID_AMD, 0x1103, NULL)) + if (!pci_dev_present(amd64nb)) return -ENODEV; /* Look for any AGP bridge */ dev = NULL; err = -ENODEV; - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev))) { + for_each_pci_dev(dev) { if (!pci_find_capability(dev, PCI_CAP_ID_AGP)) continue; /* Only one bridge supported right now */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/amd-k7-agp.c linux-2.6.10/drivers/char/agp/amd-k7-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/amd-k7-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/amd-k7-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -53,8 +53,10 @@ } global_cache_flush(); - for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) + for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { writel(agp_bridge->scratch_page, page_map->remapped+i); + readl(page_map->remapped+i); /* PCI Posting. */ + } return 0; } @@ -167,6 +169,7 @@ for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { writel(virt_to_phys(amd_irongate_private.gatt_pages[i]->real) | 1, page_dir.remapped+GET_PAGE_DIR_OFF(addr)); + readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */ } return 0; @@ -220,8 +223,8 @@ amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); /* Write out the address of the gatt table */ - OUTREG32(amd_irongate_private.registers, AMD_ATTBASE, - agp_bridge->gatt_bus_addr); + writel(agp_bridge->gatt_bus_addr, amd_irongate_private.registers+AMD_ATTBASE); + readl(amd_irongate_private.registers+AMD_ATTBASE); /* PCI Posting. */ /* Write the Sync register */ pci_write_config_byte(agp_bridge->dev, AMD_MODECNTL, 0x80); @@ -230,19 +233,19 @@ pci_write_config_byte(agp_bridge->dev, AMD_MODECNTL2, 0x00); /* Write the enable register */ - enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = readw(amd_irongate_private.registers+AMD_GARTENABLE); enable_reg = (enable_reg | 0x0004); - OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + writew(enable_reg, amd_irongate_private.registers+AMD_GARTENABLE); + readw(amd_irongate_private.registers+AMD_GARTENABLE); /* PCI Posting. */ /* Write out the size register */ pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp); - temp = (((temp & ~(0x0000000e)) | current_size->size_value) - | 0x00000001); + temp = (((temp & ~(0x0000000e)) | current_size->size_value) | 1); pci_write_config_dword(agp_bridge->dev, AMD_APSIZE, temp); /* Flush the tlb */ - OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); - + writel(1, amd_irongate_private.registers+AMD_TLBFLUSH); + readl(amd_irongate_private.registers+AMD_TLBFLUSH); /* PCI Posting.*/ return 0; } @@ -254,9 +257,10 @@ previous_size = A_SIZE_LVL2(agp_bridge->previous_size); - enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); + enable_reg = readw(amd_irongate_private.registers+AMD_GARTENABLE); enable_reg = (enable_reg & ~(0x0004)); - OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg); + writew(enable_reg, amd_irongate_private.registers+AMD_GARTENABLE); + readw(amd_irongate_private.registers+AMD_GARTENABLE); /* PCI Posting. */ /* Write back the previous size and disable gart translation */ pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp); @@ -275,7 +279,8 @@ static void amd_irongate_tlbflush(struct agp_memory *temp) { - OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); + writel(1, amd_irongate_private.registers+AMD_TLBFLUSH); + readl(amd_irongate_private.registers+AMD_TLBFLUSH); /* PCI Posting. */ } static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) @@ -310,6 +315,7 @@ addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_generic_mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); + readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } amd_irongate_tlbflush(mem); return 0; @@ -328,6 +334,7 @@ addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); + readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } amd_irongate_tlbflush(mem); @@ -471,6 +478,8 @@ static int __init agp_amdk7_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_amdk7_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/ati-agp.c linux-2.6.10/drivers/char/agp/ati-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/ati-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/ati-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -62,8 +62,6 @@ SetPageReserved(virt_to_page(page_map->real)); err = map_page_into_agp(virt_to_page(page_map->real)); - /* CACHE_FLUSH(); */ - global_cache_flush(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL || err) { @@ -75,8 +73,10 @@ /*CACHE_FLUSH();*/ global_cache_flush(); - for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { writel(agp_bridge->scratch_page, page_map->remapped+i); + readl(page_map->remapped+i); /* PCI Posting. */ + } return 0; } @@ -186,7 +186,8 @@ static void ati_tlbflush(struct agp_memory * mem) { - OUTREG32(ati_generic_private.registers, ATI_GART_CACHE_CNTRL, 1); + writel(1, ati_generic_private.registers+ATI_GART_CACHE_CNTRL); + readl(ati_generic_private.registers+ATI_GART_CACHE_CNTRL); /* PCI Posting. */ } static void ati_cleanup(void) @@ -230,15 +231,16 @@ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr); */ - OUTREG32(ati_generic_private.registers, ATI_GART_FEATURE_ID, 0x60000); + writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID); + readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/ /* SIGNALED_SYSTEM_ERROR @ NB_STATUS */ pci_read_config_dword(agp_bridge->dev, 4, &temp); pci_write_config_dword(agp_bridge->dev, 4, temp | (1<<14)); /* Write out the address of the gatt table */ - OUTREG32(ati_generic_private.registers, ATI_GART_BASE, - agp_bridge->gatt_bus_addr); + writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE); + readl(ati_generic_private.registers+ATI_GART_BASE); /* PCI Posting. */ return 0; } @@ -291,6 +293,7 @@ addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); + readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } agp_bridge->driver->tlb_flush(mem); return 0; @@ -310,6 +313,7 @@ addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); + readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } agp_bridge->driver->tlb_flush(mem); @@ -371,6 +375,7 @@ for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { writel(virt_to_bus(ati_generic_private.gatt_pages[i]->real) | 1, page_dir.remapped+GET_PAGE_DIR_OFF(addr)); + readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */ } return 0; @@ -525,6 +530,8 @@ static int __init agp_ati_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_ati_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/efficeon-agp.c linux-2.6.10/drivers/char/agp/efficeon-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/efficeon-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/efficeon-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -375,7 +375,7 @@ if (!r->start && r->end) { if(pci_assign_resource(pdev, 0)) { printk(KERN_ERR PFX "could not assign resource 0\n"); - return (-ENODEV); + return -ENODEV; } } @@ -386,7 +386,7 @@ */ if (pci_enable_device(pdev)) { printk(KERN_ERR PFX "Unable to Enable PCI device\n"); - return (-ENODEV); + return -ENODEV; } /* Fill in the mode register */ @@ -441,6 +441,9 @@ { static int agp_initialised=0; + if (agp_off) + return -EINVAL; + if (agp_initialised == 1) return 0; agp_initialised=1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/generic.c linux-2.6.10/drivers/char/agp/generic.c --- linux.vanilla-2.6.10/drivers/char/agp/generic.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/generic.c 2005-01-03 18:44:00.000000000 +0000 @@ -35,7 +35,10 @@ #include #include #include +#include #include +#include +#include #include "agp.h" __u32 *agp_gatt_table; @@ -47,6 +50,26 @@ */ EXPORT_SYMBOL_GPL(agp_memory_reserved); +#if defined(CONFIG_X86) +int map_page_into_agp(struct page *page) +{ + int i; + i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE); + global_flush_tlb(); + return i; +} +EXPORT_SYMBOL_GPL(map_page_into_agp); + +int unmap_page_from_agp(struct page *page) +{ + int i; + i = change_page_attr(page, 1, PAGE_KERNEL); + global_flush_tlb(); + return i; +} +EXPORT_SYMBOL_GPL(unmap_page_from_agp); +#endif + /* * Generic routines for handling agp_memory structures - * They use the basic page allocation routines to do the brunt of the work. @@ -181,8 +204,7 @@ agp_free_memory(new); return NULL; } - new->memory[i] = - agp_bridge->driver->mask_memory(virt_to_phys(addr), type); + new->memory[i] = virt_to_phys(addr); new->page_count++; } @@ -507,7 +529,7 @@ u32 tmp; u32 agp3; - while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) { + for_each_pci_dev(device) { cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (!cap_ptr) continue; @@ -551,7 +573,7 @@ if (agp_v3) mode *= 4; - while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) { + for_each_pci_dev(device) { u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP); if (!agp) continue; @@ -737,8 +759,10 @@ agp_bridge->gatt_bus_addr = virt_to_phys(agp_bridge->gatt_table_real); /* AK: bogus, should encode addresses > 4GB */ - for (i = 0; i < num_entries; i++) + for (i = 0; i < num_entries; i++) { writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i); + readl(agp_bridge->gatt_table+i); /* PCI Posting. */ + } return 0; } @@ -854,8 +878,10 @@ mem->is_flushed = TRUE; } - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), agp_bridge->gatt_table+j); + readl(agp_bridge->gatt_table+j); /* PCI Posting. */ + } agp_bridge->driver->tlb_flush(mem); return 0; @@ -873,9 +899,12 @@ } /* AK: bogus, should encode addresses > 4GB */ - for (i = pg_start; i < (mem->page_count + pg_start); i++) + for (i = pg_start; i < (mem->page_count + pg_start); i++) { writel(agp_bridge->scratch_page, agp_bridge->gatt_table+i); + readl(agp_bridge->gatt_table+i); /* PCI Posting. */ + } + global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; } @@ -916,7 +945,7 @@ return NULL; map_page_into_agp(page); - + get_page(page); SetPageLocked(page); atomic_inc(&agp_bridge->current_memory_agp); @@ -934,6 +963,7 @@ page = virt_to_page(addr); unmap_page_from_agp(page); + put_page(page); unlock_page(page); free_page((unsigned long)addr); @@ -958,21 +988,15 @@ EXPORT_SYMBOL(agp_enable); -#ifdef CONFIG_SMP static void ipi_handler(void *null) { flush_agp_cache(); } -#endif void global_cache_flush(void) { -#ifdef CONFIG_SMP if (on_each_cpu(ipi_handler, NULL, 1, 1) != 0) panic(PFX "timed out waiting for the other CPUs!\n"); -#else - flush_agp_cache(); -#endif } EXPORT_SYMBOL(global_cache_flush); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/hp-agp.c linux-2.6.10/drivers/char/agp/hp-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/hp-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/hp-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -88,7 +88,7 @@ * - IOVA space is 1Gb in size * - first 512Mb is IOMMU, second 512Mb is GART */ - hp->io_tlb_ps = INREG64(hp->ioc_regs, HP_ZX1_TCNFG); + hp->io_tlb_ps = readq(hp->ioc_regs+HP_ZX1_TCNFG); switch (hp->io_tlb_ps) { case 0: hp->io_tlb_shift = 12; break; case 1: hp->io_tlb_shift = 13; break; @@ -104,13 +104,13 @@ hp->io_page_size = 1 << hp->io_tlb_shift; hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size; - hp->iova_base = INREG64(hp->ioc_regs, HP_ZX1_IBASE) & ~0x1; + hp->iova_base = readq(hp->ioc_regs+HP_ZX1_IBASE) & ~0x1; hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE; hp->gart_size = HP_ZX1_GART_SIZE; hp->gatt_entries = hp->gart_size / hp->io_page_size; - hp->io_pdir = phys_to_virt(INREG64(hp->ioc_regs, HP_ZX1_PDIR_BASE)); + hp->io_pdir = phys_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE)); hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { @@ -174,7 +174,7 @@ * If the IOTLB is currently disabled, we can take it over. * Otherwise, we have to share with sba_iommu. */ - hp->io_pdir_owner = (INREG64(hp->ioc_regs, HP_ZX1_IBASE) & 0x1) == 0; + hp->io_pdir_owner = (readq(hp->ioc_regs+HP_ZX1_IBASE) & 0x1) == 0; if (hp->io_pdir_owner) return hp_zx1_ioc_owner(); @@ -189,18 +189,18 @@ u8 pos, id; int ttl = 48; - status = INREG16(hpa, PCI_STATUS); + status = readw(hpa+PCI_STATUS); if (!(status & PCI_STATUS_CAP_LIST)) return 0; - pos = INREG8(hpa, PCI_CAPABILITY_LIST); + pos = readb(hpa+PCI_CAPABILITY_LIST); while (ttl-- && pos >= 0x40) { pos &= ~3; - id = INREG8(hpa, pos + PCI_CAP_LIST_ID); + id = readb(hpa+pos+PCI_CAP_LIST_ID); if (id == 0xff) break; if (id == cap) return pos; - pos = INREG8(hpa, pos + PCI_CAP_LIST_NEXT); + pos = readb(hpa+pos+PCI_CAP_LIST_NEXT); } return 0; } @@ -217,7 +217,7 @@ hp->lba_cap_offset = hp_zx1_lba_find_capability(hp->lba_regs, PCI_CAP_ID_AGP); - cap = INREG32(hp->lba_regs, hp->lba_cap_offset) & 0xff; + cap = readl(hp->lba_regs+hp->lba_cap_offset) & 0xff; if (cap != PCI_CAP_ID_AGP) { printk(KERN_ERR PFX "Invalid capability ID 0x%02x at 0x%x\n", cap, hp->lba_cap_offset); @@ -245,15 +245,19 @@ agp_bridge->gart_bus_addr = hp->gart_base; agp_bridge->capndx = hp->lba_cap_offset; - agp_bridge->mode = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS); + agp_bridge->mode = readl(hp->lba_regs+hp->lba_cap_offset+PCI_AGP_STATUS); if (hp->io_pdir_owner) { - OUTREG64(hp->ioc_regs, HP_ZX1_PDIR_BASE, virt_to_phys(hp->io_pdir)); - OUTREG64(hp->ioc_regs, HP_ZX1_TCNFG, hp->io_tlb_ps); - OUTREG64(hp->ioc_regs, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1)); - OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, hp->iova_base | 0x1); - OUTREG64(hp->ioc_regs, HP_ZX1_PCOM, hp->iova_base | log2(HP_ZX1_IOVA_SIZE)); - INREG64(hp->ioc_regs, HP_ZX1_PCOM); + writel(virt_to_phys(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE); + readl(hp->ioc_regs+HP_ZX1_PDIR_BASE); + writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG); + readl(hp->ioc_regs+HP_ZX1_TCNFG); + writel(~(HP_ZX1_IOVA_SIZE-1), hp->ioc_regs+HP_ZX1_IMASK); + readl(hp->ioc_regs+HP_ZX1_IMASK); + writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE); + readl(hp->ioc_regs+HP_ZX1_IBASE); + writel(hp->iova_base|log2(HP_ZX1_IOVA_SIZE), hp->ioc_regs+HP_ZX1_PCOM); + readl(hp->ioc_regs+HP_ZX1_PCOM); } return 0; @@ -265,8 +269,10 @@ struct _hp_private *hp = &hp_private; if (hp->ioc_regs) { - if (hp->io_pdir_owner) - OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0); + if (hp->io_pdir_owner) { + writeq(0, hp->ioc_regs+HP_ZX1_IBASE); + readq(hp->ioc_regs+HP_ZX1_IBASE); + } iounmap(hp->ioc_regs); } if (hp->lba_regs) @@ -278,8 +284,8 @@ { struct _hp_private *hp = &hp_private; - OUTREG64(hp->ioc_regs, HP_ZX1_PCOM, hp->gart_base | log2(hp->gart_size)); - INREG64(hp->ioc_regs, HP_ZX1_PCOM); + writeq(hp->gart_base | log2(hp->gart_size), hp->ioc_regs+HP_ZX1_PCOM); + readq(hp->ioc_regs+HP_ZX1_PCOM); } static int @@ -401,12 +407,11 @@ struct _hp_private *hp = &hp_private; u32 command; - command = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS); - + command = readl(hp->lba_regs+hp->lba_cap_offset+PCI_AGP_STATUS); command = agp_collect_device_status(mode, command); command |= 0x00000100; - OUTREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_COMMAND, command); + writel(command, hp->lba_regs+hp->lba_cap_offset+PCI_AGP_COMMAND); agp_device_command(command, (mode & AGP8X_MODE) != 0); } @@ -519,6 +524,8 @@ static int __init agp_hp_init (void) { + if (agp_off) + return -EINVAL; acpi_get_devices("HWP0003", zx1_gart_probe, "HWP0003", NULL); if (hp_zx1_gart_found) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/i460-agp.c linux-2.6.10/drivers/char/agp/i460-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/i460-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/i460-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -532,8 +532,8 @@ static unsigned long i460_mask_memory (unsigned long addr, int type) { /* Make sure the returned address is a valid GATT entry */ - return (agp_bridge->driver->masks[0].mask - | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12)); + return agp_bridge->driver->masks[0].mask + | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12); } struct agp_bridge_driver intel_i460_driver = { @@ -585,6 +585,8 @@ bridge->dev = pdev; bridge->capndx = cap_ptr; + printk(KERN_INFO PFX "Detected Intel 460GX chipset\n"); + pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); } @@ -620,6 +622,8 @@ static int __init agp_intel_i460_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_intel_i460_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/intel-agp.c linux-2.6.10/drivers/char/agp/intel-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/intel-agp.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/intel-agp.c 2005-01-04 16:50:42.000000000 +0000 @@ -117,7 +117,7 @@ return -ENOMEM; } - if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL) + if ((readl(intel_i810_private.registers+I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); @@ -125,23 +125,23 @@ } pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, - agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - global_cache_flush(); + writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_i810_private.registers+I810_PGETBL_CTL); + readl(intel_i810_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { for (i = 0; i < current_size->num_entries; i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - agp_bridge->scratch_page); + writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI posting. */ } } + global_cache_flush(); return 0; } static void intel_i810_cleanup(void) { - OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0); + writel(0, intel_i810_private.registers+I810_PGETBL_CTL); + readl(intel_i810_private.registers); /* PCI Posting. */ iounmap(intel_i810_private.registers); } @@ -161,13 +161,15 @@ struct page * page; page = alloc_pages(GFP_KERNEL, 2); - if (page == NULL) { + if (page == NULL) return NULL; - } + if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { + global_flush_tlb(); __free_page(page); return NULL; } + global_flush_tlb(); get_page(page); SetPageLocked(page); atomic_inc(&agp_bridge->current_memory_agp); @@ -183,6 +185,7 @@ page = virt_to_page(addr); change_page_attr(page, 4, PAGE_KERNEL); + global_flush_tlb(); put_page(page); unlock_page(page); free_pages((unsigned long)addr, 2); @@ -211,10 +214,8 @@ /* special insert */ global_cache_flush(); for (i = pg_start; i < (pg_start + mem->page_count); i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - (i * 4096) | I810_PTE_LOCAL | - I810_PTE_VALID); + writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } global_cache_flush(); agp_bridge->driver->tlb_flush(mem); @@ -228,9 +229,9 @@ insert: global_cache_flush(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (j * 4), - agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), + intel_i810_private.registers+I810_PTE_BASE+(j*4)); + readl(intel_i810_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */ } global_cache_flush(); @@ -244,11 +245,9 @@ int i; for (i = pg_start; i < (mem->page_count + pg_start); i++) { - OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (i * 4), - agp_bridge->scratch_page); + writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } - global_cache_flush(); agp_bridge->driver->tlb_flush(mem); return 0; @@ -318,7 +317,7 @@ return new; } if (type == AGP_PHYS_MEMORY) - return(alloc_agpphysmem_i8xx(pg_count, type)); + return alloc_agpphysmem_i8xx(pg_count, type); return NULL; } @@ -387,8 +386,7 @@ gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: - rdct = INREG8(intel_i830_private.registers, - I830_RDRAM_CHANNEL_TYPE); + rdct = readb(intel_i830_private.registers+I830_RDRAM_CHANNEL_TYPE); gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); local = 1; @@ -463,10 +461,10 @@ intel_i830_private.registers = ioremap(temp,128 * 4096); if (!intel_i830_private.registers) - return (-ENOMEM); + return -ENOMEM; - temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; - global_cache_flush(); + temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ?? */ /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); @@ -475,7 +473,7 @@ agp_bridge->gatt_bus_addr = temp; - return(0); + return 0; } /* Return the gatt table to a sane state. Use the top of stolen @@ -483,7 +481,7 @@ */ static int intel_i830_free_gatt_table(void) { - return(0); + return 0; } static int intel_i830_fetch_size(void) @@ -498,7 +496,7 @@ /* 855GM/852GM/865G has 128MB aperture size */ agp_bridge->previous_size = agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 0; - return(values[0].size); + return values[0].size; } pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); @@ -506,14 +504,14 @@ if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { agp_bridge->previous_size = agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 0; - return(values[0].size); + return values[0].size; } else { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1); agp_bridge->aperture_size_idx = 1; - return(values[1].size); + return values[1].size; } - return(0); + return 0; } static int intel_i830_configure(void) @@ -532,14 +530,18 @@ gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - global_cache_flush(); + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); + readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ - if (agp_bridge->driver->needs_scratch_page) - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); + if (agp_bridge->driver->needs_scratch_page) { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ + } + } - return (0); + global_cache_flush(); + return 0; } static void intel_i830_cleanup(void) @@ -547,8 +549,7 @@ iounmap(intel_i830_private.registers); } -static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, - int type) +static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int type) { int i,j,num_entries; void *temp; @@ -561,11 +562,11 @@ pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } if ((pg_start + mem->page_count) > num_entries) - return (-EINVAL); + return -EINVAL; /* The i830 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. @@ -573,19 +574,19 @@ if ((type != 0 && type != AGP_PHYS_MEMORY) || (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return (-EINVAL); + return -EINVAL; - global_cache_flush(); + global_cache_flush(); /* FIXME: Necessary ?*/ - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), - agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), + intel_i830_private.registers+I810_PTE_BASE+(j*4)); + readl(intel_i830_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */ + } global_cache_flush(); - agp_bridge->driver->tlb_flush(mem); - - return(0); + return 0; } static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -597,26 +598,26 @@ if (pg_start < intel_i830_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } - for (i = pg_start; i < (mem->page_count + pg_start); i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ + } global_cache_flush(); - agp_bridge->driver->tlb_flush(mem); - - return (0); + return 0; } static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) { if (type == AGP_PHYS_MEMORY) - return(alloc_agpphysmem_i8xx(pg_count, type)); + return alloc_agpphysmem_i8xx(pg_count, type); /* always return NULL for other allocation types for now */ - return(NULL); + return NULL; } static int intel_i915_configure(void) @@ -636,15 +637,18 @@ gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - global_cache_flush(); - + writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_i830_private.registers); + readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) - OUTREG32(intel_i830_private.gtt, i, agp_bridge->scratch_page); + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); + readl(intel_i830_private.gtt+i); /* PCI Posting. */ + } } - return (0); + global_cache_flush(); + return 0; } static void intel_i915_cleanup(void) @@ -667,11 +671,11 @@ pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } if ((pg_start + mem->page_count) > num_entries) - return (-EINVAL); + return -EINVAL; /* The i830 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. @@ -679,18 +683,18 @@ if ((type != 0 && type != AGP_PHYS_MEMORY) || (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return (-EINVAL); + return -EINVAL; global_cache_flush(); - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.gtt, j, agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), intel_i830_private.gtt+j); + readl(intel_i830_private.gtt+j); /* PCI Posting. */ + } global_cache_flush(); - agp_bridge->driver->tlb_flush(mem); - - return(0); + return 0; } static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -702,17 +706,17 @@ if (pg_start < intel_i830_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } - for (i = pg_start; i < (mem->page_count + pg_start); i++) - OUTREG32(intel_i830_private.gtt, i, agp_bridge->scratch_page); + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); + readl(intel_i830_private.gtt+i); + } global_cache_flush(); - agp_bridge->driver->tlb_flush(mem); - - return (0); + return 0; } static int intel_i915_fetch_size(void) @@ -730,7 +734,7 @@ else offset = 2; /* 256MB aperture */ agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); - return(values[offset].size); + return values[offset].size; } /* The intel i915 automatically initializes the agp aperture during POST. @@ -753,16 +757,16 @@ intel_i830_private.gtt = ioremap(temp2, 256 * 1024); if (!intel_i830_private.gtt) - return (-ENOMEM); + return -ENOMEM; temp &= 0xfff80000; intel_i830_private.registers = ioremap(temp,128 * 4096); if (!intel_i830_private.registers) - return (-ENOMEM); + return -ENOMEM; - temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; - global_cache_flush(); + temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); @@ -771,7 +775,7 @@ agp_bridge->gatt_bus_addr = temp; - return(0); + return 0; } static int intel_fetch_size(void) @@ -1493,7 +1497,7 @@ { struct pci_dev *i810_dev; - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); + i810_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); if (!i810_dev) return 0; intel_i810_private.i810_dev = i810_dev; @@ -1504,9 +1508,9 @@ { struct pci_dev *i830_dev; - i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); + i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) { - i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, i830_dev); } @@ -1715,6 +1719,7 @@ { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + pci_dev_put(pdev); agp_remove_bridge(bridge); agp_put_bridge(bridge); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/intel-mch-agp.c linux-2.6.10/drivers/char/agp/intel-mch-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/intel-mch-agp.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/intel-mch-agp.c 2005-01-03 18:44:00.000000000 +0000 @@ -51,7 +51,7 @@ if (new == NULL) return NULL; - new->memory[0] = agp_bridge->driver->mask_memory(virt_to_phys(addr), type); + new->memory[0] = virt_to_phys(addr); new->page_count = 1; new->num_scratch_pages = 1; new->type = AGP_PHYS_MEMORY; @@ -111,8 +111,7 @@ gtt_entries = MB(8) - KB(132); break; case I830_GMCH_GMS_LOCAL: - rdct = INREG8(intel_i830_private.registers, - I830_RDRAM_CHANNEL_TYPE); + rdct = readb(intel_i830_private.registers+I830_RDRAM_CHANNEL_TYPE); gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); local = 1; @@ -174,10 +173,10 @@ intel_i830_private.registers = (volatile u8 __iomem*) ioremap(temp,128 * 4096); if (!intel_i830_private.registers) - return (-ENOMEM); + return -ENOMEM; - temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; - global_cache_flush(); + temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ?? */ /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); @@ -186,7 +185,7 @@ agp_bridge->gatt_bus_addr = temp; - return(0); + return 0; } /* Return the gatt table to a sane state. Use the top of stolen @@ -194,7 +193,7 @@ */ static int intel_i830_free_gatt_table(void) { - return(0); + return 0; } static int intel_i830_fetch_size(void) @@ -209,7 +208,7 @@ /* 855GM/852GM/865G has 128MB aperture size */ agp_bridge->previous_size = agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 0; - return(values[0].size); + return values[0].size; } pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); @@ -217,14 +216,14 @@ if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { agp_bridge->previous_size = agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 0; - return(values[0].size); + return values[0].size; } else { agp_bridge->previous_size = agp_bridge->current_size = (void *) values; agp_bridge->aperture_size_idx = 1; - return(values[1].size); + return values[1].size; } - return(0); + return 0; } static int intel_i830_configure(void) @@ -243,14 +242,17 @@ gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - global_cache_flush(); - - if (agp_bridge->driver->needs_scratch_page) - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); + readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ - return (0); + if (agp_bridge->driver->needs_scratch_page) { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ + } + } + global_cache_flush(); + return 0; } static void intel_i830_cleanup(void) @@ -272,11 +274,11 @@ pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } if ((pg_start + mem->page_count) > num_entries) - return (-EINVAL); + return -EINVAL; /* The i830 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. @@ -284,19 +286,21 @@ if ((type != 0 && type != AGP_PHYS_MEMORY) || (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return (-EINVAL); + return -EINVAL; - global_cache_flush(); + global_cache_flush(); /* FIXME: ?? */ - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), - agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), + intel_i830_private.registers+I810_PTE_BASE+(j*4)); + readl(intel_i830_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */ + } global_cache_flush(); agp_bridge->driver->tlb_flush(mem); - return(0); + return 0; } static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -308,26 +312,26 @@ if (pg_start < intel_i830_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); - return (-EINVAL); + return -EINVAL; } - for (i = pg_start; i < (mem->page_count + pg_start); i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ + } global_cache_flush(); - agp_bridge->driver->tlb_flush(mem); - - return (0); + return 0; } static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) { if (type == AGP_PHYS_MEMORY) - return(alloc_agpphysmem_i8xx(pg_count, type)); + return alloc_agpphysmem_i8xx(pg_count, type); /* always return NULL for other allocation types for now */ - return(NULL); + return NULL; } static int intel_8xx_fetch_size(void) @@ -470,9 +474,9 @@ { struct pci_dev *i830_dev; - i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); + i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) { - i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, i830_dev); } @@ -536,7 +540,7 @@ if (!r->start && r->end) { if(pci_assign_resource(pdev, 0)) { printk(KERN_ERR PFX "could not assign resource 0\n"); - return (-ENODEV); + return -ENODEV; } } @@ -547,7 +551,7 @@ */ if (pci_enable_device(pdev)) { printk(KERN_ERR PFX "Unable to Enable PCI device\n"); - return (-ENODEV); + return -ENODEV; } /* Fill in the mode register */ @@ -565,6 +569,7 @@ { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + pci_dev_put(pdev); agp_remove_bridge(bridge); agp_put_bridge(bridge); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/isoch.c linux-2.6.10/drivers/char/agp/isoch.c --- linux.vanilla-2.6.10/drivers/char/agp/isoch.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/isoch.c 2005-01-03 18:36:30.000000000 +0000 @@ -347,7 +347,7 @@ INIT_LIST_HEAD(head); /* Find all AGP devices, and add them to dev_list. */ - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) { mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); if (mcapndx == 0) continue; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/nvidia-agp.c linux-2.6.10/drivers/char/agp/nvidia-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/nvidia-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/nvidia-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -214,9 +214,11 @@ global_cache_flush(); mem->is_flushed = TRUE; } - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(mem->memory[i], mem->type), agp_bridge->gatt_table+nvidia_private.pg_offset+j); + readl(agp_bridge->gatt_table+nvidia_private.pg_offset+j); /* PCI Posting. */ + } agp_bridge->driver->tlb_flush(mem); return 0; } @@ -403,6 +405,8 @@ static int __init agp_nvidia_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_nvidia_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/sis-agp.c linux-2.6.10/drivers/char/agp/sis-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/sis-agp.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/sis-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -340,6 +340,8 @@ static int __init agp_sis_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_sis_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/sworks-agp.c linux-2.6.10/drivers/char/agp/sworks-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/sworks-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/sworks-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -242,12 +242,12 @@ */ static void serverworks_tlbflush(struct agp_memory *temp) { - OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 1); - while(INREG8(serverworks_private.registers, SVWRKS_POSTFLUSH) == 1) + writeb(1, serverworks_private.registers+SVWRKS_POSTFLUSH); + while (readb(serverworks_private.registers+SVWRKS_POSTFLUSH) == 1) cpu_relax(); - OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 1); - while(INREG32(serverworks_private.registers, SVWRKS_DIRFLUSH) == 1) + writel(1, serverworks_private.registers+SVWRKS_DIRFLUSH); + while(readl(serverworks_private.registers+SVWRKS_DIRFLUSH) == 1) cpu_relax(); } @@ -269,21 +269,21 @@ return -ENOMEM; } - OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a); + writeb(0xA, serverworks_private.registers+SVWRKS_GART_CACHE); + readb(serverworks_private.registers+SVWRKS_GART_CACHE); /* PCI Posting. */ - OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE, - agp_bridge->gatt_bus_addr); + writel(agp_bridge->gatt_bus_addr, serverworks_private.registers+SVWRKS_GATTBASE); + readl(serverworks_private.registers+SVWRKS_GATTBASE); /* PCI Posting. */ - cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND); + cap_reg = readw(serverworks_private.registers+SVWRKS_COMMAND); cap_reg &= ~0x0007; cap_reg |= 0x4; - OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg); + writew(cap_reg, serverworks_private.registers+SVWRKS_COMMAND); + readw(serverworks_private.registers+SVWRKS_COMMAND); - pci_read_config_byte(serverworks_private.svrwrks_dev, - SVWRKS_AGP_ENABLE, &enable_reg); + pci_read_config_byte(serverworks_private.svrwrks_dev,SVWRKS_AGP_ENABLE, &enable_reg); enable_reg |= 0x1; /* Agp Enable bit */ - pci_write_config_byte(serverworks_private.svrwrks_dev, - SVWRKS_AGP_ENABLE, enable_reg); + pci_write_config_byte(serverworks_private.svrwrks_dev,SVWRKS_AGP_ENABLE, enable_reg); serverworks_tlbflush(NULL); agp_bridge->capndx = pci_find_capability(serverworks_private.svrwrks_dev, PCI_CAP_ID_AGP); @@ -539,6 +539,8 @@ static int __init agp_serverworks_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_serverworks_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/uninorth-agp.c linux-2.6.10/drivers/char/agp/uninorth-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/uninorth-agp.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/uninorth-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -373,6 +373,8 @@ static int __init agp_uninorth_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_uninorth_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/agp/via-agp.c linux-2.6.10/drivers/char/agp/via-agp.c --- linux.vanilla-2.6.10/drivers/char/agp/via-agp.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/agp/via-agp.c 2005-01-03 18:44:49.000000000 +0000 @@ -523,6 +523,8 @@ static int __init agp_via_init(void) { + if (agp_off) + return -EINVAL; return pci_module_init(&agp_via_pci_driver); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/isicom.c linux-2.6.10/drivers/char/isicom.c --- linux.vanilla-2.6.10/drivers/char/isicom.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/isicom.c 2005-01-06 18:53:25.000000000 +0000 @@ -16,10 +16,81 @@ * * 10/6/99 sameer Merged the ISA and PCI drivers to * a new unified driver. + * + * 3/9/99 sameer Added support for ISI4616 cards. + * + * 16/9/99 sameer We do not force RTS low anymore. + * This is to prevent the firmware + * from getting confused. + * + * 26/10/99 sameer Cosmetic changes:The driver now + * dumps the Port Count information + * along with I/O address and IRQ. + * + * 13/12/99 sameer Fixed the problem with IRQ sharing. + * + * 10/5/00 sameer Fixed isicom_shutdown_board() + * to not lower DTR on all the ports + * when the last port on the card is + * closed. + * + * 10/5/00 sameer Signal mask setup command added + * to isicom_setup_port and + * isicom_shutdown_port. + * + * 24/5/00 sameer The driver is now SMP aware. + * + * + * 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem + * + * + * 03/01/01 anil .s Added support for resetting the + * internal modems on ISI cards. + * + * 08/02/01 anil .s Upgraded the driver for kernel + * 2.4.x + * + * 11/04/01 Kevin Fixed firmware load problem with + * ISIHP-4X card + * + * 30/04/01 anil .s Fixed the remote login through + * ISI port problem. Now the link + * does not go down before password + * prompt. + * + * 03/05/01 anil .s Fixed the problem with IRQ sharing + * among ISI-PCI cards. + * + * 03/05/01 anil .s Added support to display the version + * info during insmod as well as module + * listing by lsmod. + * + * 10/05/01 anil .s Done the modifications to the source + * file and Install script so that the + * same installation can be used for + * 2.2.x and 2.4.x kernel. + * + * 06/06/01 anil .s Now we drop both dtr and rts during + * shutdown_port as well as raise them + * during isicom_config_port. + * * 09/06/01 acme@conectiva.com.br use capable, not suser, do * restore_flags on failure in * isicom_send_break, verify put_user * result + * + * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps + * Baud index extended to 21 + * + * 20/03/03 ranjeeth Made to work for Linux Advanced server. + * Taken care of license warning. + * + * 10/12/03 Ravindra Made to work for Fedora Core 1 of + * Red Hat Distribution + * + * 06/01/05 Alan Cox Merged the ISI and base kernel strands + * into a single 2.6 driver + * * *********************************************************** * * To use this driver you also need the support package. You @@ -35,6 +106,10 @@ * * Omit those entries for boards you don't have installed. * + * TODO + * Hotplug + * Merge testing + * 64-bit verification */ #include @@ -74,7 +149,6 @@ MODULE_DEVICE_TABLE(pci, isicom_pci_tbl); static int prev_card = 3; /* start servicing isi_card[0] */ -static struct isi_board * irq_to_board[16]; static struct tty_driver *isicom_normal; static struct isi_board isi_card[BOARD_COUNT]; @@ -101,9 +175,205 @@ 18, 19 }; +struct isi_board { + unsigned short base; + unsigned char irq; + unsigned char port_count; + unsigned short status; + unsigned short port_status; /* each bit represents a single port */ + unsigned short shift_count; + struct isi_port * ports; + signed char count; + unsigned char isa; + spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */ + unsigned long flags; +}; + +struct isi_port { + unsigned short magic; + unsigned int flags; + int count; + int blocked_open; + int close_delay; + unsigned short channel; + unsigned short status; + unsigned short closing_wait; + struct isi_board * card; + struct tty_struct * tty; + wait_queue_head_t close_wait; + wait_queue_head_t open_wait; + struct work_struct hangup_tq; + struct work_struct bh_tqueue; + unsigned char * xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; +}; + +/* + * Locking functions for card level locking. We need to own both + * the kernel lock for the card and have the card in a position that + * it wants to talk. + */ + +static int lock_card(struct isi_board *card) +{ + char retries; + unsigned short base = card->base; + + for (retries = 0; retries < 100; retries++) { + spin_lock_irqsave(&card->card_lock, card->flags); + if (inw(base + 0xe) & 0x1) { + return 1; + } else { + spin_unlock_irqrestore(&card->card_lock, card->flags); + udelay(1000); /* 1ms */ + } + } + printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%x)\n", card->base); + return 0; /* Failed to aquire the card! */ +} + +static int lock_card_at_interrupt(struct isi_board *card) +{ + unsigned char retries; + unsigned short base = card->base; + + for (retries = 0; retries < 200; retries++) { + spin_lock_irqsave(&card->card_lock, card->flags); + + if (inw(base + 0xe) & 0x1) + return 1; + else + spin_unlock_irqrestore(&card->card_lock, card->flags); + } + /* Failing in interrupt is an acceptable event */ + return 0; /* Failed to aquire the card! */ +} + +static void unlock_card(struct isi_board *card) +{ + spin_unlock_irqrestore(&card->card_lock, card->flags); +} + +/* + * ISI Card specific ops ... + */ + +static void raise_dtr(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + + if (!lock_card(card)) + return; + + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0504, base); + InterruptTheCard(base); + port->status |= ISI_DTR; + unlock_card(card); +} + +static inline void drop_dtr(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + + if (!lock_card(card)) + return; + + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0404, base); + InterruptTheCard(base); + port->status &= ~ISI_DTR; + unlock_card(card); +} + +static inline void raise_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + + if (!lock_card(card)) + return; + + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0a04, base); + InterruptTheCard(base); + port->status |= ISI_RTS; + unlock_card(card); +} +static inline void drop_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + + if (!lock_card(card)) + return; + + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0804, base); + InterruptTheCard(base); + port->status &= ~ISI_RTS; + unlock_card(card); +} + +static inline void raise_dtr_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + + if (!lock_card(card)) + return; + + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0f04, base); + InterruptTheCard(base); + port->status |= (ISI_DTR | ISI_RTS); + unlock_card(card); +} + +static void drop_dtr_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + + if (!lock_card(card)) + return; + + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0c04, base); + InterruptTheCard(base); + port->status &= ~(ISI_RTS | ISI_DTR); + unlock_card(card); +} + +static inline void kill_queue(struct isi_port * port, short queue) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + + if (!lock_card(card)) + return; + + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw((queue << 8) | 0x06, base); + InterruptTheCard(base); + unlock_card(card); +} + + /* - * Firmware loader driver specific routines - * + * Firmware loader driver specific routines. This needs to mostly die + * and be replaced with request_firmware. */ static struct file_operations ISILoad_fops = { @@ -354,15 +624,19 @@ return 0; } -/* Transmitter */ +/* + * Transmitter. + * + * We shovel data into the card buffers on a regular basis. The card + * will do the rest of the work for us. + */ static void isicom_tx(unsigned long _data) { short count = (BOARD_COUNT-1), card, base; - short txcount, wait, wrd, residue, word_count, cnt; + short txcount, wrd, residue, word_count, cnt; struct isi_port * port; struct tty_struct * tty; - unsigned long flags; #ifdef ISICOM_DEBUG ++tx_count; @@ -384,33 +658,29 @@ port = isi_card[card].ports; base = isi_card[card].base; for (;count > 0;count--, port++) { + if (!lock_card_at_interrupt(&isi_card[card])) + continue; /* port not active or tx disabled to force flow control */ - if (!(port->status & ISI_TXOK)) + if (!(port->flags & ASYNC_INITIALIZED) || + !(port->status & ISI_TXOK)) + unlock_card(&isi_card[card]); continue; tty = port->tty; - save_flags(flags); cli(); - txcount = min_t(short, TX_SIZE, port->xmit_cnt); - if ((txcount <= 0) || tty->stopped || tty->hw_stopped) { - restore_flags(flags); + + + if(tty == NULL) { + unlock_card(&isi_card[card]); continue; } - wait = 200; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - restore_flags(flags); -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_tx:Card(0x%x) found busy.\n", - card); -#endif + + txcount = min_t(short, TX_SIZE, port->xmit_cnt); + if (txcount <= 0 || tty->stopped || tty->hw_stopped) { + unlock_card(&isi_card[card]); continue; } if (!(inw(base + 0x02) & (1 << port->channel))) { - restore_flags(flags); -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_tx: cannot tx to 0x%x:%d.\n", - base, port->channel + 1); -#endif + unlock_card(&isi_card[card]); continue; } #ifdef ISICOM_DEBUG @@ -459,10 +729,10 @@ port->status &= ~ISI_TXOK; if (port->xmit_cnt <= WAKEUP_CHARS) schedule_work(&port->bh_tqueue); - restore_flags(flags); + unlock_card(&isi_card[card]); } - /* schedule another tx for hopefully in about 10ms */ + /* schedule another tx for hopefully in about 10ms */ sched_again: if (!re_schedule) return; @@ -490,7 +760,10 @@ wake_up_interruptible(&tty->write_wait); } -/* main interrupt handler routine */ +/* + * Main interrupt handler routine + */ + static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -501,31 +774,19 @@ unsigned char channel; short byte_count; - /* - * find the source of interrupt - */ - - for(count = 0; count < BOARD_COUNT; count++) { - card = &isi_card[count]; - if (card->base != 0) { - if (((card->isa == YES) && (card->irq == irq)) || - ((card->isa == NO) && (card->irq == irq) && (inw(card->base+0x0e) & 0x02))) - break; - } - card = NULL; - } + card = (struct isi_board *) dev_id; - if (!card || !(card->status & FIRMWARE_LOADED)) { -/* printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);*/ + if (!card || !(card->status & FIRMWARE_LOADED)) return IRQ_NONE; - } base = card->base; + spin_lock(&card->card_lock); + if (card->isa == NO) { - /* - * disable any interrupts from the PCI card and lower the - * interrupt line - */ + /* + * disable any interrupts from the PCI card and lower the + * interrupt line + */ outw(0x8000, base+0x04); ClearInterrupt(base); } @@ -534,16 +795,15 @@ header = inw(base); channel = (header & 0x7800) >> card->shift_count; byte_count = header & 0xff; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM:Intr:(0x%x:%d).\n", base, channel+1); -#endif - if ((channel+1) > card->port_count) { + + if (channel + 1 > card->port_count) { printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n", base, channel+1); if (card->isa) ClearInterrupt(base); else outw(0x0000, base+0x04); /* enable interrupts */ + spin_unlock(&card->card_lock); return IRQ_HANDLED; } port = card->ports + channel; @@ -556,6 +816,21 @@ } tty = port->tty; + if (tty == NULL) { + word_count = byte_count >> 1; + while(byte_count > 1) { + inw(base); + byte_count -= 2; + } + if (byte_count & 0x01) + inw(base); + if (card->isa == YES) + ClearInterrupt(base); + else + outw(0x0000, base+0x04); /* enable interrupts */ + spin_unlock(&card->card_lock); + return IRQ_HANDLED; + } if (header & 0x8000) { /* Status Packet */ header = inw(base); @@ -631,7 +906,6 @@ if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; *tty->flip.flag_buf_ptr++ = TTY_BREAK; - /* dunno if this is right */ *tty->flip.char_buf_ptr++ = 0; tty->flip.count++; if (port->flags & ASYNC_SAK) @@ -683,13 +957,12 @@ return IRQ_HANDLED; } - /* called with interrupts disabled */ static void isicom_config_port(struct isi_port * port) { struct isi_board * card = port->card; struct tty_struct * tty; unsigned long baud; - unsigned short channel_setup, wait, base = card->base; + unsigned short channel_setup, base = card->base; unsigned short channel = port->channel, shift_count = card->shift_count; unsigned char flow_ctrl; @@ -729,40 +1002,36 @@ else raise_dtr(port); - wait = 100; - while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); - if (!wait) { - printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at channel setup.\n"); - return; - } - outw(0x8000 | (channel << shift_count) |0x03, base); - outw(linuxb_to_isib[baud] << 8 | 0x03, base); - channel_setup = 0; - switch(C_CSIZE(tty)) { - case CS5: - channel_setup |= ISICOM_CS5; - break; - case CS6: - channel_setup |= ISICOM_CS6; - break; - case CS7: - channel_setup |= ISICOM_CS7; - break; - case CS8: - channel_setup |= ISICOM_CS8; - break; - } - - if (C_CSTOPB(tty)) - channel_setup |= ISICOM_2SB; - - if (C_PARENB(tty)) - channel_setup |= ISICOM_EVPAR; - if (C_PARODD(tty)) - channel_setup |= ISICOM_ODPAR; - outw(channel_setup, base); - InterruptTheCard(base); - + if (lock_card(card)) { + outw(0x8000 | (channel << shift_count) |0x03, base); + outw(linuxb_to_isib[baud] << 8 | 0x03, base); + channel_setup = 0; + switch(C_CSIZE(tty)) { + case CS5: + channel_setup |= ISICOM_CS5; + break; + case CS6: + channel_setup |= ISICOM_CS6; + break; + case CS7: + channel_setup |= ISICOM_CS7; + break; + case CS8: + channel_setup |= ISICOM_CS8; + break; + } + + if (C_CSTOPB(tty)) + channel_setup |= ISICOM_2SB; + if (C_PARENB(tty)) { + channel_setup |= ISICOM_EVPAR; + if (C_PARODD(tty)) + channel_setup |= ISICOM_ODPAR; + } + outw(channel_setup, base); + InterruptTheCard(base); + unlock_card(card); + } if (C_CLOCAL(tty)) port->flags &= ~ASYNC_CHECK_CD; else @@ -780,23 +1049,19 @@ if (I_IXOFF(tty)) flow_ctrl |= ISICOM_INITIATE_XONXOFF; - wait = 100; - while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); - if (!wait) { - printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at flow setup.\n"); - return; - } - outw(0x8000 | (channel << shift_count) |0x04, base); - outw(flow_ctrl << 8 | 0x05, base); - outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); - InterruptTheCard(base); + if (lock_card(card)) { + outw(0x8000 | (channel << shift_count) |0x04, base); + outw(flow_ctrl << 8 | 0x05, base); + outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); + InterruptTheCard(base); + unlock_card(card); + } /* rx enabled -> enable port for rx on the card */ if (C_CREAD(tty)) { card->port_status |= (1 << channel); outw(card->port_status, base + 0x02); } - } /* open et all */ @@ -807,22 +1072,16 @@ struct isi_port * port; unsigned long flags; - if (bp->status & BOARD_ACTIVE) + spin_lock_irqsave(&bp->card_lock, flags); + if (bp->status & BOARD_ACTIVE) { + spin_unlock_irqrestore(&bp->card_lock, flags); return; - port = bp->ports; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts start, port_count %d...\n", bp->port_count); -#endif - for(channel = 0; channel < bp->port_count; channel++, port++) { - save_flags(flags); cli(); - drop_dtr_rts(port); - restore_flags(flags); } -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts stop...\n"); -#endif - + port = bp->ports; bp->status |= BOARD_ACTIVE; + spin_unlock_irqrestore(&bp->card_lock, flags); + for(channel = 0; channel < bp->port_count; channel++, port++) + drop_dtr_rts(port); return; } @@ -831,8 +1090,9 @@ struct isi_board * card = port->card; unsigned long flags; - if (port->flags & ASYNC_INITIALIZED) + if (port->flags & ASYNC_INITIALIZED) { return 0; + } if (!port->xmit_buf) { unsigned long page; @@ -845,7 +1105,8 @@ } port->xmit_buf = (unsigned char *) page; } - save_flags(flags); cli(); + + spin_lock_irqsave(&card->card_lock, flags); if (port->tty) clear_bit(TTY_IO_ERROR, &port->tty->flags); if (port->count == 1) @@ -858,15 +1119,16 @@ isicom_config_port(port); port->flags |= ASYNC_INITIALIZED; - - restore_flags(flags); + spin_unlock_irqrestore(&card->card_lock, flags); return 0; } static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port) { + struct isi_board * card = port->card; int do_clocal = 0, retval; + unsigned long flags; DECLARE_WAITQUEUE(wait, current); /* block if port is in the process of being closed */ @@ -894,49 +1156,34 @@ if (C_CLOCAL(tty)) do_clocal = 1; -#ifdef ISICOM_DEBUG - if (do_clocal) - printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n"); -#endif /* block waiting for DCD to be asserted, and while callout dev is busy */ retval = 0; add_wait_queue(&port->open_wait, &wait); - cli(); - if (!tty_hung_up_p(filp)) - port->count--; - sti(); + + spin_lock_irqsave(&card->card_lock, flags); + if (!tty_hung_up_p(filp)) + port->count--; port->blocked_open++; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: waiting for DCD...\n"); -#endif + spin_unlock_irqrestore(&card->card_lock, flags); + while (1) { - cli(); raise_dtr_rts(port); - sti(); + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: tty_hung_up_p || not init.\n"); -#endif break; } if (!(port->flags & ASYNC_CLOSING) && (do_clocal || (port->status & ISI_DCD))) { -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n"); -#endif break; } if (signal_pending(current)) { -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: sig blocked.\n"); -#endif retval = -ERESTARTSYS; break; } @@ -944,9 +1191,11 @@ } set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); + spin_lock_irqsave(&card->card_lock, flags); if (!tty_hung_up_p(filp)) port->count++; port->blocked_open--; + spin_unlock_irqrestore(&card->card_lock, flags); if (retval) return retval; port->flags |= ASYNC_NORMAL_ACTIVE; @@ -960,62 +1209,33 @@ unsigned int line, board; int error; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: open start!!!.\n"); -#endif line = tty->index; - -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "line = %d.\n", line); -#endif - - if ((line < 0) || (line > (PORT_COUNT-1))) + if (line < 0 || line > PORT_COUNT-1) return -ENODEV; board = BOARD(line); - -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "board = %d.\n", board); -#endif - card = &isi_card[board]; - if (!(card->status & FIRMWARE_LOADED)) { -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board); -#endif + + if (!(card->status & FIRMWARE_LOADED)) return -ENODEV; - } /* open on a port greater than the port count for the card !!! */ - if (line > ((board * 16) + card->port_count - 1)) { - printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n"); + if (line > ((board * 16) + card->port_count - 1)) return -ENODEV; - } + port = &isi_ports[line]; if (isicom_paranoia_check(port, tty->name, "isicom_open")) return -ENODEV; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n"); -#endif isicom_setup_board(card); port->count++; tty->driver_data = port; port->tty = tty; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n"); -#endif if ((error = isicom_setup_port(port))!=0) return error; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready ...\n"); -#endif if ((error = block_til_ready(tty, filp, port))!=0) return error; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: open end!!!.\n"); -#endif return 0; } @@ -1023,38 +1243,50 @@ static inline void isicom_shutdown_board(struct isi_board * bp) { - int channel; - struct isi_port * port; - - if (!(bp->status & BOARD_ACTIVE)) - return; - bp->status &= ~BOARD_ACTIVE; - port = bp->ports; - for(channel = 0; channel < bp->port_count; channel++, port++) { - drop_dtr_rts(port); - } + unsigned long flags; + + spin_lock_irqsave(&bp->card_lock, flags); + if (bp->status & BOARD_ACTIVE) { + bp->status &= ~BOARD_ACTIVE; + } + spin_unlock_irqrestore(&bp->card_lock, flags); } static void isicom_shutdown_port(struct isi_port * port) { struct isi_board * card = port->card; struct tty_struct * tty; + unsigned long flags; - if (!(port->flags & ASYNC_INITIALIZED)) + tty = port->tty; + + spin_lock_irqsave(&card->card_lock, flags); + if (!(port->flags & ASYNC_INITIALIZED)) { + spin_unlock_irqrestore(&card->card_lock, flags); return; + } if (port->xmit_buf) { free_page((unsigned long) port->xmit_buf); port->xmit_buf = NULL; } - if (!(tty = port->tty) || C_HUPCL(tty)) + port->flags &= ~ASYNC_INITIALIZED; + /* 3rd October 2000 : Vinayak P Risbud */ + port->tty = 0; + spin_unlock_irqrestore(&card->card_lock, flags); + + /*Fix done by Anil .S on 30-04-2001 + remote login through isi port has dtr toggle problem + due to which the carrier drops before the password prompt + appears on the remote end. Now we drop the dtr only if the + HUPCL(Hangup on close) flag is set for the tty*/ + + if (C_HUPCL(tty)) /* drop dtr on this port */ drop_dtr(port); /* any other port uninits */ - if (tty) set_bit(TTY_IO_ERROR, &tty->flags); - port->flags &= ~ASYNC_INITIALIZED; if (--card->count < 0) { printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n", @@ -1063,8 +1295,10 @@ } /* last port was closed , shutdown that boad too */ - if (!card->count) - isicom_shutdown_board(card); + if(C_HUPCL(tty)) { + if (!card->count) + isicom_shutdown_board(card); + } } static void isicom_close(struct tty_struct * tty, struct file * filp) @@ -1082,13 +1316,13 @@ printk(KERN_DEBUG "ISICOM: Close start!!!.\n"); #endif - save_flags(flags); cli(); + spin_lock_irqsave(&card->card_lock, flags); if (tty_hung_up_p(filp)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } - if ((tty->count == 1) && (port->count != 1)) { + if (tty->count == 1 && port->count != 1) { printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count" "tty->count = 1 port count = %d.\n", card->base, port->count); @@ -1102,41 +1336,46 @@ } if (port->count) { - restore_flags(flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } port->flags |= ASYNC_CLOSING; tty->closing = 1; + spin_unlock_irqrestore(&card->card_lock, flags); + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, port->closing_wait); /* indicate to the card that no more data can be received on this port */ + spin_lock_irqsave(&card->card_lock, flags); if (port->flags & ASYNC_INITIALIZED) { card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); } isicom_shutdown_port(port); + spin_unlock_irqrestore(&card->card_lock, flags); + if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - tty_ldisc_flush(tty); + + spin_lock_irqsave(&card->card_lock, flags); tty->closing = 0; - port->tty = NULL; + if (port->blocked_open) { + spin_unlock_irqrestore(&card->card_lock, flags); if (port->close_delay) { #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: scheduling until time out.\n"); #endif msleep_interruptible(jiffies_to_msecs(port->close_delay)); } + spin_lock_irqsave(&card->card_lock, flags); wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); - restore_flags(flags); -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: Close end!!!.\n"); -#endif + spin_unlock_irqrestore(&card->card_lock, flags); } /* write et all */ @@ -1144,21 +1383,19 @@ const unsigned char * buf, int count) { struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; unsigned long flags; int cnt, total = 0; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n", - port->channel+1, count); -#endif + if (isicom_paranoia_check(port, tty->name, "isicom_write")) return 0; if (!tty || !port->xmit_buf || !tmp_buf) return 0; - save_flags(flags); + spin_lock_irqsave(&card->card_lock, flags); + while(1) { - cli(); cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (cnt <= 0) @@ -1167,17 +1404,13 @@ memcpy(port->xmit_buf + port->xmit_head, buf, cnt); port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1); port->xmit_cnt += cnt; - restore_flags(flags); buf += cnt; count -= cnt; total += cnt; } if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) port->status |= ISI_TXOK; - restore_flags(flags); -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total); -#endif + spin_unlock_irqrestore(&card->card_lock, flags); return total; } @@ -1185,6 +1418,7 @@ static void isicom_put_char(struct tty_struct * tty, unsigned char ch) { struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_put_char")) @@ -1192,21 +1426,17 @@ if (!tty || !port->xmit_buf) return; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch); -#endif - - save_flags(flags); cli(); - - if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) { - restore_flags(flags); + + spin_lock_irqsave(&card->card_lock, flags); + if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + spin_unlock_irqrestore(&card->card_lock, flags); return; } port->xmit_buf[port->xmit_head++] = ch; port->xmit_head &= (SERIAL_XMIT_SIZE - 1); port->xmit_cnt++; - restore_flags(flags); + spin_unlock_irqrestore(&card->card_lock, flags); } /* flush_chars et all */ @@ -1217,8 +1447,7 @@ if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars")) return; - if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !port->xmit_buf) + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf) return; /* this tells the transmitter to consider this port for @@ -1231,6 +1460,7 @@ { struct isi_port * port = (struct isi_port *) tty->driver_data; int free; + if (isicom_paranoia_check(port, tty->name, "isicom_write_room")) return 0; @@ -1253,21 +1483,17 @@ static inline void isicom_send_break(struct isi_port * port, unsigned long length) { struct isi_board * card = port->card; - short wait = 10; unsigned short base = card->base; - unsigned long flags; - save_flags(flags); cli(); - while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); - if (!wait) { - printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n"); - goto out; - } + if(!lock_card(card)) + return; + outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); outw((length & 0xff) << 8 | 0x00, base); outw((length & 0xff00), base); InterruptTheCard(base); -out: restore_flags(flags); + + unlock_card(card); } static int isicom_tiocmget(struct tty_struct *tty, struct file *file) @@ -1291,12 +1517,10 @@ unsigned int set, unsigned int clear) { struct isi_port * port = (struct isi_port *) tty->driver_data; - unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; - save_flags(flags); cli(); if (set & TIOCM_RTS) raise_rts(port); if (set & TIOCM_DTR) @@ -1307,7 +1531,6 @@ if (clear & TIOCM_DTR) drop_dtr(port); - restore_flags(flags); return 0; } @@ -1315,7 +1538,6 @@ struct serial_struct __user *info) { struct serial_struct newinfo; - unsigned long flags; int reconfig_port; if(copy_from_user(&newinfo, info, sizeof(newinfo))) @@ -1340,9 +1562,7 @@ (newinfo.flags & ASYNC_FLAGS)); } if (reconfig_port) { - save_flags(flags); cli(); isicom_config_port(port); - restore_flags(flags); } return 0; } @@ -1421,7 +1641,6 @@ static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios) { struct isi_port * port = (struct isi_port *) tty->driver_data; - unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) return; @@ -1430,9 +1649,7 @@ tty->termios->c_iflag == old_termios->c_iflag) return; - save_flags(flags); cli(); isicom_config_port(port); - restore_flags(flags); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1446,16 +1663,13 @@ { struct isi_port * port = (struct isi_port *) tty->driver_data; struct isi_board * card = port->card; - unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_throttle")) return; /* tell the card that this port cannot handle any more data for now */ - save_flags(flags); cli(); card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); - restore_flags(flags); } /* unthrottle et all */ @@ -1463,16 +1677,13 @@ { struct isi_port * port = (struct isi_port *) tty->driver_data; struct isi_board * card = port->card; - unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle")) return; /* tell the card that this port is ready to accept more data */ - save_flags(flags); cli(); card->port_status |= (1 << port->channel); outw(card->port_status, card->base + 0x02); - restore_flags(flags); } /* stop et all */ @@ -1509,7 +1720,7 @@ tty = port->tty; if (tty) - tty_hangup(tty); /* FIXME: module removal race here - AKPM */ + tty_hangup(tty); } static void isicom_hangup(struct tty_struct * tty) @@ -1530,21 +1741,22 @@ static void isicom_flush_buffer(struct tty_struct * tty) { struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&card->card_lock, flags); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - restore_flags(flags); + spin_unlock_irqrestore(&card->card_lock, flags); wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } -static int register_ioregion(void) +static int __init register_ioregion(void) { int count, done=0; for (count=0; count < BOARD_COUNT; count++ ) { @@ -1559,7 +1771,7 @@ return done; } -static void unregister_ioregion(void) +static void __exit unregister_ioregion(void) { int count; for (count=0; count < BOARD_COUNT; count++ ) @@ -1591,7 +1803,7 @@ .tiocmset = isicom_tiocmset, }; -static int register_drivers(void) +static int __init register_drivers(void) { int error; @@ -1622,7 +1834,7 @@ return 0; } -static void unregister_drivers(void) +static void __exit unregister_drivers(void) { int error = tty_unregister_driver(isicom_normal); if (error) @@ -1630,78 +1842,48 @@ put_tty_driver(isicom_normal); } -static int register_isr(void) +static int __init register_isr(void) { - int count, done=0, card; - int flag; - unsigned char request; + int count, done=0; + unsigned long irqflags; + for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { - /* - * verify if the required irq has already been requested for - * another ISI Card, if so we already have it, else request it - */ - request = YES; - for(card = 0; card < count; card++) - if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { - request = NO; - if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO)) - break; - /* - * ISA cards cannot share interrupts with other - * PCI or ISA devices hence disable this card. - */ + irqflags = (isi_card[count].isa == YES) ? + SA_INTERRUPT : + (SA_INTERRUPT | SA_SHIRQ); + + if (request_irq(isi_card[count].irq, + isicom_interrupt, + irqflags, + ISICOM_NAME, &isi_card[count])) { + + printk(KERN_WARNING "ISICOM: Could not" + " install handler at Irq %d." + " Card%d will be disabled.\n", + isi_card[count].irq, count+1); + release_region(isi_card[count].base,16); - isi_card[count].base = 0; - break; - } - flag=0; - if(isi_card[count].isa == NO) - flag |= SA_SHIRQ; - - if (request == YES) { - if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT|flag, ISICOM_NAME, NULL)) { - printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", - isi_card[count].irq, count+1); - release_region(isi_card[count].base,16); - isi_card[count].base=0; - } - else { - printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", - count+1, isi_card[count].base, isi_card[count].irq); - - irq_to_board[isi_card[count].irq]=&isi_card[count]; - done++; - } + isi_card[count].base=0; } + else + done++; } } return done; } -static void unregister_isr(void) +static void __exit unregister_isr(void) { - int count, card; - unsigned char freeirq; + int count; + for (count=0; count < BOARD_COUNT; count++ ) { - if (isi_card[count].base) { - freeirq = YES; - for(card = 0; card < count; card++) - if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { - freeirq = NO; - break; - } - if (freeirq == YES) { - free_irq(isi_card[count].irq, NULL); -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); -#endif - } - } + if (isi_card[count].base) + free_irq(isi_card[count].irq, &isi_card[count]); } } -static int isicom_init(void) +static int __init isicom_init(void) { int card, channel, base; struct isi_port * port; @@ -1744,11 +1926,12 @@ for (card = 0; card < BOARD_COUNT; card++) { port = &isi_ports[card * 16]; isi_card[card].ports = port; + spin_lock_init(&isi_card[card].card_lock); base = isi_card[card].base; for (channel = 0; channel < 16; channel++, port++) { port->magic = ISICOM_MAGIC; port->card = &isi_card[card]; - port->channel = channel; + port->channel = channel; port->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; INIT_WORK(&port->hangup_tq, do_isicom_hangup, port); @@ -1778,7 +1961,7 @@ module_param_array(irq, int, NULL, 0); MODULE_PARM_DESC(irq, "Interrupts for the cards"); -int init_module(void) +static int __devinit isicom_setup(void) { struct pci_dev *dev = NULL; int retval, card, idx, count; @@ -1878,38 +2061,19 @@ return 0; } -void cleanup_module(void) +static void __exit isicom_exit(void) { re_schedule = 0; + /* FIXME */ msleep(1000); - -#ifdef ISICOM_DEBUG - printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count); -#endif - -#ifdef ISICOM_DEBUG - printk("ISICOM: uregistering isr ...\n"); -#endif unregister_isr(); - -#ifdef ISICOM_DEBUG - printk("ISICOM: unregistering drivers ...\n"); -#endif unregister_drivers(); - -#ifdef ISICOM_DEBUG - printk("ISICOM: unregistering ioregion ...\n"); -#endif unregister_ioregion(); - -#ifdef ISICOM_DEBUG - printk("ISICOM: freeing tmp_buf ...\n"); -#endif - free_page((unsigned long)tmp_buf); - -#ifdef ISICOM_DEBUG - printk("ISICOM: unregistering firmware loader ...\n"); -#endif + if(tmp_buf) + free_page((unsigned long)tmp_buf); if (misc_deregister(&isiloader_device)) printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); } + +module_init(isicom_setup); +module_exit(isicom_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/Kconfig linux-2.6.10/drivers/char/Kconfig --- linux.vanilla-2.6.10/drivers/char/Kconfig 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/Kconfig 2005-01-06 18:42:17.000000000 +0000 @@ -203,7 +203,7 @@ config ISI tristate "Multi-Tech multiport card support (EXPERIMENTAL)" - depends on SERIAL_NONSTANDARD && PCI && EXPERIMENTAL && BROKEN_ON_SMP && m + depends on SERIAL_NONSTANDARD help This is a driver for the Multi-Tech cards which provide several serial ports. The driver is experimental and can currently only be diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/moxa.c linux-2.6.10/drivers/char/moxa.c --- linux.vanilla-2.6.10/drivers/char/moxa.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/moxa.c 2004-12-28 16:52:06.000000000 +0000 @@ -174,8 +174,8 @@ /* statusflags */ #define TXSTOPPED 0x1 #define LOWWAIT 0x2 -#define EMPTYWAIT 0x4 -#define THROTTLE 0x8 +#define EMPTYWAIT 0x3 +#define THROTTLE 0x4 /* event */ #define MOXA_EVENT_HANGUP 1 @@ -216,7 +216,6 @@ static struct timer_list moxaTimer; static int moxaEmptyTimer_on[MAX_PORTS]; static struct timer_list moxaEmptyTimer[MAX_PORTS]; -static struct semaphore moxaBuffSem; /* * static functions: @@ -337,7 +336,6 @@ if (!moxaDriver) return -ENOMEM; - init_MUTEX(&moxaBuffSem); moxaDriver->owner = THIS_MODULE; moxaDriver->name = "ttya"; moxaDriver->devfs_name = "tts/a"; @@ -528,21 +526,6 @@ tty->driver_data = NULL; return (-ENODEV); } - down(&moxaBuffSem); - if (!moxaXmitBuff) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - up(&moxaBuffSem); - return (-ENOMEM); - } - /* This test is guarded by the BuffSem so no longer needed - delete me in 2.5 */ - if (moxaXmitBuff) - free_page(page); - else - moxaXmitBuff = (unsigned char *) page; - } - up(&moxaBuffSem); ch = &moxaChannels[port]; ch->count++; @@ -645,17 +628,13 @@ if (ch == NULL) return (0); port = ch->port; - save_flags(flags); - cli(); + + spin_lock_irqsave(&ch->lock, flags); len = MoxaPortWriteData(port, (unsigned char *) buf, count); - restore_flags(flags); + set_bit(LOWWAIT, &ch->statusflags); + spin_unlock_irqrestore(&ch->lock, flags); - /********************************************* - if ( !(ch->statusflags & LOWWAIT) && - ((len != count) || (MoxaPortTxFree(port) <= 100)) ) - ************************************************/ - ch->statusflags |= LOWWAIT; - return (len); + return len; } static int moxa_write_room(struct tty_struct *tty) @@ -692,14 +671,14 @@ * routine. And since the open() failed, we return 0 here. TDJ */ if (ch == NULL) - return (0); + return 0; chars = MoxaPortTxQueue(ch->port); if (chars) { /* * Make it possible to wakeup anything waiting for output * in tty_ioctl.c, etc. */ - if (!(ch->statusflags & EMPTYWAIT)) + if (!test_bit(EMPTYWAIT, &ch->statusflags)) setup_empty_event(tty); } return (chars); @@ -723,15 +702,11 @@ if (ch == NULL) return; port = ch->port; - save_flags(flags); - cli(); + spin_lock_irqsave(&ch->lock, flags); moxaXmitBuff[0] = c; MoxaPortWriteData(port, moxaXmitBuff, 1); - restore_flags(flags); - /************************************************ - if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) - *************************************************/ - ch->statusflags |= LOWWAIT; + set_bit(LOWWAIT, &ch->statusflags); + spin_unlock_irqrestore(&ch->lock, flags); } static int moxa_tiocmget(struct tty_struct *tty, struct file *file) @@ -841,14 +816,13 @@ { struct moxa_str *ch = (struct moxa_str *) tty->driver_data; - ch->statusflags |= THROTTLE; + set_bit(THROTTLE, &ch->statusflags); } static void moxa_unthrottle(struct tty_struct *tty) { struct moxa_str *ch = (struct moxa_str *) tty->driver_data; - - ch->statusflags &= ~THROTTLE; + clear_bit(THROTTLE, &ch->statusflags); } static void moxa_set_termios(struct tty_struct *tty, @@ -871,7 +845,7 @@ if (ch == NULL) return; MoxaPortTxDisable(ch->port); - ch->statusflags |= TXSTOPPED; + set_bit(TXSTOPPED, &ch->statusflags); } @@ -882,11 +856,11 @@ if (ch == NULL) return; - if (!(ch->statusflags & TXSTOPPED)) + if (!test_bit(TXSTOPPED, &ch->statusflags)) return; MoxaPortTxEnable(ch->port); - ch->statusflags &= ~TXSTOPPED; + clear_bit(TXSTOPPED, &ch->statusflags); } static void moxa_hangup(struct tty_struct *tty) @@ -926,12 +900,12 @@ for (i = 0; i < ports; i++, ch++) { if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) continue; - if (!(ch->statusflags & THROTTLE) && + if (!test_bit(THROTTLE, &ch->statusflags) && (MoxaPortRxQueue(ch->port) > 0)) receive_data(ch); if ((tp = ch->tty) == 0) continue; - if (ch->statusflags & LOWWAIT) { + if (test_bit(LOWWAIT, &ch->statusflags)) { if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { if (!tp->stopped) { ch->statusflags &= ~LOWWAIT; @@ -1080,15 +1054,14 @@ struct moxa_str *ch = tty->driver_data; unsigned long flags; - save_flags(flags); - cli(); - ch->statusflags |= EMPTYWAIT; + spin_lock_irqsave(&ch->lock, flags); + set_bit(EMPTYWAIT, &ch->statusflags);; moxaEmptyTimer_on[ch->port] = 0; del_timer(&moxaEmptyTimer[ch->port]); moxaEmptyTimer[ch->port].expires = jiffies + HZ; moxaEmptyTimer_on[ch->port] = 1; add_timer(&moxaEmptyTimer[ch->port]); - restore_flags(flags); + spin_unlock_irqrestore(&ch->lock, flags); } static void check_xmit_empty(unsigned long data) @@ -1098,9 +1071,9 @@ ch = (struct moxa_str *) data; moxaEmptyTimer_on[ch->port] = 0; del_timer(&moxaEmptyTimer[ch->port]); - if (ch->tty && (ch->statusflags & EMPTYWAIT)) { + if (ch->tty && test_bit(EMPTYWAIT, &ch->statusflags)) { if (MoxaPortTxQueue(ch->port) == 0) { - ch->statusflags &= ~EMPTYWAIT; + clear_bit(EMPTYWAIT, &ch->statusflags); tty_wakeup(ch->tty); return; } @@ -1108,7 +1081,7 @@ moxaEmptyTimer_on[ch->port] = 1; add_timer(&moxaEmptyTimer[ch->port]); } else - ch->statusflags &= ~EMPTYWAIT; + clear_bit(EMPTYWAIT, &ch->statusflags); } static void shut_down(struct moxa_str *ch) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/mxser.c linux-2.6.10/drivers/char/mxser.c --- linux.vanilla-2.6.10/drivers/char/mxser.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/mxser.c 2004-12-29 22:45:56.000000000 +0000 @@ -401,7 +401,7 @@ static void mxser_flush_chars(struct tty_struct *); static void mxser_put_char(struct tty_struct *, unsigned char); static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong); -static int mxser_ioctl_special(unsigned int, unsigned long); +static int mxser_ioctl_special(unsigned int, void __user *); static void mxser_throttle(struct tty_struct *); static void mxser_unthrottle(struct tty_struct *); static void mxser_set_termios(struct tty_struct *, struct termios *); @@ -417,9 +417,9 @@ static int mxser_startup(struct mxser_struct *); static void mxser_shutdown(struct mxser_struct *); static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios); -static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *); -static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *); -static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *); +static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *); +static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *); +static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *); static void mxser_send_break(struct mxser_struct *, int); static int mxser_tiocmget(struct tty_struct *, struct file *); static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int); @@ -834,6 +834,7 @@ } /* start finding PCI board here */ +#ifdef CONFIG_PCI n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1; index = 0; b = 0; @@ -875,6 +876,7 @@ m++; } } +#endif ret1 = 0; if (!(ret1 = tty_register_driver(mxvar_sdriver))) { @@ -968,7 +970,7 @@ *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; - mxser_change_speed(info, 0); + mxser_change_speed(info, NULL); } info->session = current->signal->session; @@ -1084,7 +1086,7 @@ tty->closing = 0; info->event = 0; - info->tty = 0; + info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { set_current_state(TASK_INTERRUPTIBLE); @@ -1223,12 +1225,13 @@ struct mxser_struct *info = (struct mxser_struct *) tty->driver_data; int retval; struct async_icount cprev, cnow; /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ + struct serial_icounter_struct __user *p_cuser; unsigned long templ; unsigned long flags; + void __user *argp = (void __user *)arg; if (tty->index == MXSER_PORTS) - return (mxser_ioctl_special(cmd, arg)); + return (mxser_ioctl_special(cmd, argp)); // following add by Victor Yu. 01-05-2004 if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { @@ -1239,7 +1242,7 @@ p = info->port % 4; if (cmd == MOXA_SET_OP_MODE) { - if (get_user(opmode, (int *) arg)) + if (get_user(opmode, (int __user *) argp)) return -EFAULT; if (opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE) return -EFAULT; @@ -1253,7 +1256,7 @@ shiftbit = p * 2; opmode = inb(info->opmode_ioaddr) >> shiftbit; opmode &= OP_MODE_MASK; - if (copy_to_user((int *) arg, &opmode, sizeof(int))) + if (copy_to_user(argp, &opmode, sizeof(int))) return -EFAULT; } return 0; @@ -1281,19 +1284,19 @@ mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4); return (0); case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp); case TIOCSSOFTCAR: - if (get_user(templ, (unsigned long *) arg)) + if (get_user(templ, (unsigned long __user *) argp)) return -EFAULT; arg = templ; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return (0); case TIOCGSERIAL: - return (mxser_get_serial_info(info, (struct serial_struct *) arg)); + return mxser_get_serial_info(info, argp); case TIOCSSERIAL: - return (mxser_set_serial_info(info, (struct serial_struct *) arg)); + return mxser_set_serial_info(info, argp); case TIOCSERGETLSR: /* Get line status register */ - return (mxser_get_lsr_info(info, (unsigned int *) arg)); + return mxser_get_lsr_info(info, argp); /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -1340,7 +1343,7 @@ spin_lock_irqsave(&info->slock, flags); cnow = info->icount; spin_unlock_irqrestore(&info->slock, flags); - p_cuser = (struct serial_icounter_struct *) arg; + p_cuser = argp; /* modified by casper 1/11/2000 */ if (put_user(cnow.frame, &p_cuser->frame)) return -EFAULT; @@ -1364,7 +1367,7 @@ /* */ return 0; case MOXA_HighSpeedOn: - return put_user(info->baud_base != 115200 ? 1 : 0, (int *) arg); + return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *) argp); case MOXA_SDS_RSTICOUNTER:{ info->mon_data.rxcnt = 0; @@ -1374,13 +1377,13 @@ // (above) added by James. case MOXA_ASPP_SETBAUD:{ long baud; - if (get_user(baud, (long *) arg)) + if (get_user(baud, (long __user *) argp)) return -EFAULT; mxser_set_baud(info, baud); return 0; } case MOXA_ASPP_GETBAUD: - if (copy_to_user((long *) arg, &info->realbaud, sizeof(long))) + if (copy_to_user(argp, &info->realbaud, sizeof(long))) return -EFAULT; return 0; @@ -1394,7 +1397,7 @@ len += (lsr ? 0 : 1); - if (copy_to_user((int *) arg, &len, sizeof(int))) + if (copy_to_user(argp, &len, sizeof(int))) return -EFAULT; return 0; @@ -1423,7 +1426,7 @@ info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; - if (copy_to_user((struct mxser_mon *) arg, &(info->mon_data), sizeof(struct mxser_mon))) + if (copy_to_user(argp, &info->mon_data, sizeof(struct mxser_mon))) return -EFAULT; return 0; @@ -1431,7 +1434,7 @@ } case MOXA_ASPP_LSTATUS:{ - if (copy_to_user((struct mxser_mon *) arg, &(info->err_shadow), sizeof(unsigned char))) + if (copy_to_user(argp, &info->err_shadow, sizeof(unsigned char))) return -EFAULT; info->err_shadow = 0; @@ -1440,10 +1443,10 @@ } case MOXA_SET_BAUD_METHOD:{ int method; - if (get_user(method, (int *) arg)) + if (get_user(method, (int __user *) argp)) return -EFAULT; mxser_set_baud_method[info->port] = method; - if (copy_to_user((int *) arg, &method, sizeof(int))) + if (copy_to_user(argp, &method, sizeof(int))) return -EFAULT; return 0; @@ -1454,22 +1457,26 @@ return 0; } -static int mxser_ioctl_special(unsigned int cmd, unsigned long arg) +#ifndef CMSPAR +#define CMSPAR 010000000000 +#endif + +static int mxser_ioctl_special(unsigned int cmd, void __user *argp) { int i, result, status; switch (cmd) { case MOXA_GET_CONF: - if (copy_to_user((struct mxser_hwconf *) arg, mxsercfg, sizeof(struct mxser_hwconf) * 4)) + if (copy_to_user(argp, mxsercfg, sizeof(struct mxser_hwconf) * 4)) return -EFAULT; return 0; case MOXA_GET_MAJOR: - if (copy_to_user((int *) arg, &ttymajor, sizeof(int))) + if (copy_to_user(argp, &ttymajor, sizeof(int))) return -EFAULT; return 0; case MOXA_GET_CUMAJOR: - if (copy_to_user((int *) arg, &calloutmajor, sizeof(int))) + if (copy_to_user(argp, &calloutmajor, sizeof(int))) return -EFAULT; return 0; @@ -1479,9 +1486,9 @@ if (mxvar_table[i].base) result |= (1 << i); } - return put_user(result, (unsigned long *) arg); + return put_user(result, (unsigned long __user *) argp); case MOXA_GETDATACOUNT: - if (copy_to_user((struct mxser_log *) arg, &mxvar_log, sizeof(mxvar_log))) + if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log))) return -EFAULT; return (0); case MOXA_GETMSTATUS: @@ -1516,7 +1523,7 @@ else GMStatus[i].cts = 0; } - if (copy_to_user((struct mxser_mstatus *) arg, GMStatus, sizeof(struct mxser_mstatus) * MXSER_PORTS)) + if (copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MXSER_PORTS)) return -EFAULT; return 0; case MOXA_ASPP_MON_EXT:{ @@ -1584,7 +1591,7 @@ mon_data_ext.iftype[i] = opmode; } - if (copy_to_user((struct mxser_mon_ext *) arg, &mon_data_ext, sizeof(struct mxser_mon_ext))) + if (copy_to_user(argp, &mon_data_ext, sizeof(struct mxser_mon_ext))) return -EFAULT; return 0; @@ -1829,7 +1836,7 @@ info->event = 0; info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = 0; + info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1866,7 +1873,7 @@ int pass_counter = 0; int handled = IRQ_NONE; - port = 0; + port = NULL; //spin_lock(&gm_lock); for (i = 0; i < MXSER_BOARDS; i++) { @@ -2412,7 +2419,7 @@ * and set the speed of the serial port */ spin_unlock_irqrestore(&info->slock, flags); - mxser_change_speed(info, 0); + mxser_change_speed(info, NULL); info->flags |= ASYNC_INITIALIZED; return (0); @@ -2442,7 +2449,7 @@ */ if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; + info->xmit_buf = NULL; } info->IER = 0; @@ -2591,9 +2598,6 @@ cval |= 0x04; if (cflag & PARENB) cval |= UART_LCR_PARITY; -#ifndef CMSPAR -#define CMSPAR 010000000000 -#endif if (!(cflag & PARODD)) { cval |= UART_LCR_EPAR; } @@ -2807,7 +2811,7 @@ * friends of mxser_ioctl() * ------------------------------------------------------------ */ -static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct *retinfo) +static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct __user *retinfo) { struct serial_struct tmp; @@ -2829,7 +2833,7 @@ return (0); } -static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct *new_info) +static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info) { struct serial_struct new_serial; unsigned int flags; @@ -2869,7 +2873,7 @@ /* */ if (info->flags & ASYNC_INITIALIZED) { if (flags != (info->flags & ASYNC_SPD_MASK)) { - mxser_change_speed(info, 0); + mxser_change_speed(info, NULL); } } else { retval = mxser_startup(info); @@ -2887,7 +2891,7 @@ * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */ -static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value) +static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int __user *value) { unsigned char status; unsigned int result; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/tty_io.c linux-2.6.10/drivers/char/tty_io.c --- linux.vanilla-2.6.10/drivers/char/tty_io.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/char/tty_io.c 2005-01-04 19:42:29.000000000 +0000 @@ -918,9 +918,11 @@ lock_kernel(); + down(&tty_sem); tty = current->signal->tty; if (tty) { tty_pgrp = tty->pgrp; + up(&tty_sem); if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { @@ -928,6 +930,7 @@ kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit); kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit); } + up(&tty_sem); unlock_kernel(); return; } @@ -937,15 +940,19 @@ kill_pg(tty_pgrp, SIGCONT, on_exit); } + /* Must lock changes to tty_old_pgrp */ + down(&tty_sem); current->signal->tty_old_pgrp = 0; tty->session = 0; tty->pgrp = -1; + /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { p->signal->tty = NULL; } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); read_unlock(&tasklist_lock); + up(&tty_sem); unlock_kernel(); } @@ -1171,12 +1178,6 @@ struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; int retval=0; - /* - * Check whether we need to acquire the tty semaphore to avoid - * race conditions. For now, play it safe. - */ - down(&tty_sem); - /* check whether we're reopening an existing tty */ if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { tty = devpts_get_tty(idx); @@ -1365,7 +1366,6 @@ /* All paths come through here to release the semaphore */ end_init: - up(&tty_sem); return retval; /* Release locally allocated memory ... nothing placed in slots */ @@ -1561,9 +1561,14 @@ * each iteration we avoid any problems. */ while (1) { + /* Guard against races with tty->count changes elsewhere and + opens on /dev/tty */ + + down(&tty_sem); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); + up(&tty_sem); do_sleep = 0; if (tty_closing) { @@ -1599,6 +1604,8 @@ * both sides, and we've completed the last operation that could * block, so it's safe to proceed with closing. */ + + down(&tty_sem); if (pty_master) { if (--o_tty->count < 0) { printk(KERN_WARNING "release_dev: bad pty slave count " @@ -1612,7 +1619,8 @@ tty->count, tty_name(tty, buf)); tty->count = 0; } - + up(&tty_sem); + /* * We've decremented tty->count, so we need to remove this file * descriptor off the tty->tty_files list; this serves two @@ -1759,10 +1767,14 @@ noctty = filp->f_flags & O_NOCTTY; index = -1; retval = 0; + + down(&tty_sem); if (device == MKDEV(TTYAUX_MAJOR,0)) { - if (!current->signal->tty) + if (!current->signal->tty) { + up(&tty_sem); return -ENXIO; + } driver = current->signal->tty->driver; index = current->signal->tty->index; filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ @@ -1787,14 +1799,18 @@ noctty = 1; goto got_driver; } + up(&tty_sem); return -ENODEV; } driver = get_tty_driver(device, &index); - if (!driver) + if (!driver) { + up(&tty_sem); return -ENODEV; + } got_driver: retval = init_dev(driver, index, &tty); + up(&tty_sem); if (retval) return retval; @@ -1880,7 +1896,10 @@ } up(&allocated_ptys_lock); + down(&tty_sem); retval = init_dev(ptm_driver, index, &tty); + up(&tty_sem); + if (retval) goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/char/watchdog/alim7101_wdt.c linux-2.6.10/drivers/char/watchdog/alim7101_wdt.c --- linux.vanilla-2.6.10/drivers/char/watchdog/alim7101_wdt.c 2004-12-25 21:14:12.000000000 +0000 +++ linux-2.6.10/drivers/char/watchdog/alim7101_wdt.c 2004-12-26 17:25:46.000000000 +0000 @@ -12,6 +12,11 @@ * because this particular WDT has a very short timeout (1.6 * seconds) and it would be insane to count on any userspace * daemon always getting scheduled within that time frame. + * + * Additions: + * Aug 23, 2004 - Added use_gpio module parameter for use on revision a1d PMUs + * found on very old cobalt hardware. + * -- Mike Waychison */ #include @@ -38,6 +43,8 @@ #define WDT_DISABLE 0x8C #define ALI_7101_WDT 0x92 +#define ALI_7101_GPIO 0x7D +#define ALI_7101_GPIO_O 0x7E #define ALI_WDT_ARM 0x01 /* @@ -57,6 +64,10 @@ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); +static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */ +module_param(use_gpio, int, 0); +MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)"); + static void wdt_timer_ping(unsigned long); static struct timer_list timer; static unsigned long next_heartbeat; @@ -90,6 +101,13 @@ pci_read_config_byte(alim7101_pmu, 0x92, &tmp); pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp + | 0x20); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp + & ~0x20); + } } else { printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } @@ -106,11 +124,21 @@ { char tmp; - pci_read_config_byte(alim7101_pmu, 0x92, &tmp); - if (writeval == WDT_ENABLE) + pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp); + if (writeval == WDT_ENABLE) { pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); - else + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20); + } + + } else { pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20); + } + } } static void wdt_startup(void) @@ -334,7 +362,13 @@ return -EBUSY; } pci_read_config_byte(ali1543_south, 0x5e, &tmp); - if ((tmp & 0x1e) != 0x12) { + if ((tmp & 0x1e) == 0x00) { + if (!use_gpio) { + printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); + return -EBUSY; + } + nowayout = 1; + } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); return -EBUSY; } @@ -364,6 +398,10 @@ goto err_out_miscdev; } + if (nowayout) { + __module_get(THIS_MODULE); + } + printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n", timeout, nowayout); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/i2c/busses/i2c-i801.c linux-2.6.10/drivers/i2c/busses/i2c-i801.c --- linux.vanilla-2.6.10/drivers/i2c/busses/i2c-i801.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/i2c/busses/i2c-i801.c 2005-01-03 21:50:06.000000000 +0000 @@ -30,6 +30,7 @@ 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) 6300ESB 25A4 ICH6 266A + ICH7 27DA This driver supports several versions of Intel's I/O Controller Hubs (ICH). For SMBus support, they are similar to the PIIX4 and are part of Intel's '810' and other chipsets. @@ -596,6 +597,12 @@ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_ICH7_17, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { 0, } }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/i2c/busses/Kconfig linux-2.6.10/drivers/i2c/busses/Kconfig --- linux.vanilla-2.6.10/drivers/i2c/busses/Kconfig 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/i2c/busses/Kconfig 2005-01-03 21:50:06.000000000 +0000 @@ -112,6 +112,7 @@ 82801EB 6300ESB ICH6 + ICH7 This driver can also be built as a module. If so, the module will be called i2c-i801. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/arm/icside.c linux-2.6.10/drivers/ide/arm/icside.c --- linux.vanilla-2.6.10/drivers/ide/arm/icside.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/arm/icside.c 2004-12-26 21:51:12.000000000 +0000 @@ -531,9 +531,9 @@ hwif->ide_dma_off_quietly = icside_dma_off_quietly; hwif->ide_dma_host_on = icside_dma_host_on; hwif->ide_dma_on = icside_dma_on; - hwif->dma_setup = icside_dma_setup; - hwif->dma_exec_cmd = icside_dma_exec_cmd; - hwif->dma_start = icside_dma_start; + hwif->ide_dma_setup = icside_dma_setup; + hwif->ide_dma_exec_cmd = icside_dma_exec_cmd; + hwif->ide_dma_start = icside_dma_start; hwif->ide_dma_end = icside_dma_end; hwif->ide_dma_test_irq = icside_dma_test_irq; hwif->ide_dma_timeout = icside_dma_timeout; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/cris/ide-v10.c linux-2.6.10/drivers/ide/cris/ide-v10.c --- linux.vanilla-2.6.10/drivers/ide/cris/ide-v10.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/cris/ide-v10.c 2004-12-26 21:51:28.000000000 +0000 @@ -332,9 +332,9 @@ hwif->atapi_output_bytes = &e100_atapi_output_bytes; hwif->ide_dma_check = &e100_dma_check; hwif->ide_dma_end = &e100_dma_end; - hwif->dma_setup = &e100_dma_setup; - hwif->dma_exec_cmd = &e100_dma_exec_cmd; - hwif->dma_start = &e100_dma_start; + hwif->ide_dma_setup = &e100_dma_setup; + hwif->ide_dma_exec_cmd = &e100_dma_exec_cmd; + hwif->ide_dma_start = &e100_dma_start; hwif->OUTB = &etrax100_ide_outb; hwif->OUTW = &etrax100_ide_outw; hwif->OUTBSYNC = &etrax100_ide_outbsync; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide.c linux-2.6.10/drivers/ide/ide.c --- linux.vanilla-2.6.10/drivers/ide/ide.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide.c 2004-12-26 22:14:05.000000000 +0000 @@ -175,6 +175,7 @@ static int initializing; /* set while initializing built-in drivers */ DECLARE_MUTEX(ide_cfg_sem); +EXPORT_SYMBOL_GPL(ide_cfg_sem); spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; #ifdef CONFIG_BLK_DEV_IDEPCI @@ -205,11 +206,13 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index) { unsigned int unit; + unsigned int key = hwif->key; /* bulk initialize hwif & drive info with zeros */ memset(hwif, 0, sizeof(ide_hwif_t)); /* fill in any non-zero initial values */ + hwif->key = key + 1; /* Protected by ide_cfg_sem */ hwif->index = index; hwif->major = ide_hwif_to_major[index]; @@ -320,6 +323,92 @@ #endif } +/* + * ide_drive_from_key - turn key into drive + * @kval: persistent key + * + * Convert a key into a drive. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +ide_drive_t *ide_drive_from_key(void *kval) +{ + unsigned long key = (unsigned long) kval; + int idx = (key >> 8) & 0xFF; + int drive = key & 3; + ide_hwif_t *hwif = &ide_hwifs[idx]; + ide_drive_t *ret; + + key >>= 16; + + if(hwif->configured == 0 || hwif->present == 0 || hwif->drives[drive].dead || hwif->key != key) + ret = NULL; + else + ret = &ide_hwifs[idx].drives[drive]; + + return ret; +} + +EXPORT_SYMBOL_GPL(ide_drive_from_key); + +/* + * ide_drive_to_key - turn drive to persistent key + * @drive: drive to use + * + * Convert drive into a key. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +void *ide_drive_to_key(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long val; + + val = (hwif->index << 8) | (hwif->key << 16) | drive->select.b.unit; + return (void *)val; +} + +/* + * ide_hwif_from_key - turn key into hwif + * @kval: persistent key + * + * Convert a key into a drive. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +ide_hwif_t *ide_hwif_from_key(void *kval) +{ + unsigned long key = (unsigned long) kval; + int idx = (key >> 8) & 0xFF; + ide_hwif_t *hwif = &ide_hwifs[idx]; + + key >>= 16; + + if(hwif->configured == 0 || hwif->present == 0 || hwif->key != key) + return NULL; + return hwif; +} + +/* + * ide_hwif_to_key - turn drive to persistent key + * @hwif: hwif to use + * + * Convert drive into a key. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +void *ide_hwif_to_key(ide_hwif_t *hwif) +{ + unsigned long val; + + val = (hwif->index << 8) | (hwif->key << 16); + return (void *)val; +} + /** * ide_system_bus_speed - guess bus speed * @@ -495,11 +584,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); @@ -509,7 +603,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); @@ -525,7 +619,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) @@ -689,9 +783,9 @@ hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes; hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes; - hwif->dma_setup = tmp_hwif->dma_setup; - hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd; - hwif->dma_start = tmp_hwif->dma_start; + hwif->ide_dma_setup = tmp_hwif->ide_dma_setup; + hwif->ide_dma_exec_cmd = tmp_hwif->ide_dma_exec_cmd; + hwif->ide_dma_start = tmp_hwif->ide_dma_start; hwif->ide_dma_end = tmp_hwif->ide_dma_end; hwif->ide_dma_check = tmp_hwif->ide_dma_check; hwif->ide_dma_on = tmp_hwif->ide_dma_on; @@ -744,14 +838,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 @@ -761,26 +857,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]; @@ -790,9 +899,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]; @@ -803,27 +920,35 @@ destroy_proc_ide_interface(hwif); + 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 * the hwgroup if we were the only member @@ -836,6 +961,14 @@ } if (!drive->present) continue; + + /* + * The hwgroup chain is IRQ touched. We must protect + * walking this from an IDE event for another device + * in the chain + */ + + spin_lock_irq(&ide_lock); if (drive == drive->next) { /* special case: last drive from hwgroup. */ BUG_ON(hwgroup->drive != drive); @@ -852,47 +985,67 @@ hwgroup->hwif = HWIF(hwgroup->drive); } } + spin_unlock_irq(&ide_lock); + + /* + * The rest of the cleanup is private + */ + BUG_ON(hwgroup->drive == drive); if (drive->id != NULL) { kfree(drive->id); drive->id = NULL; } drive->present = 0; - /* Messed up locking ... */ - spin_unlock_irq(&ide_lock); blk_cleanup_queue(drive->queue); device_unregister(&drive->gendev); down(&drive->gendev_rel_sem); - spin_lock_irq(&ide_lock); drive->queue = NULL; } - if (hwif->next == hwif) { - BUG_ON(hwgroup->hwif != hwif); - kfree(hwgroup); - } else { - /* There is another interface in hwgroup. - * Unlink us, and set hwgroup->drive and ->hwif to - * something sane. - */ - g = hwgroup->hwif; - while (g->next != hwif) - g = g->next; - g->next = hwif->next; - if (hwgroup->hwif == hwif) { - /* Chose a random hwif for hwgroup->hwif. - * It's guaranteed that there are no drives - * left in the hwgroup. + /* + * Lock against hwgroup walkers including interrupts off other + * IDE devices wile we unhook ourselves. + */ + + spin_lock_irq(&ide_lock); + + if (hwgroup) + { + if (hwif->next == hwif) { + BUG_ON(hwgroup->hwif != hwif); + kfree(hwgroup); + } else { + /* There is another interface in hwgroup. + * Unlink us, and set hwgroup->drive and ->hwif to + * something sane. */ - BUG_ON(hwgroup->drive != NULL); - hwgroup->hwif = g; + g = hwgroup->hwif; + while (g->next != hwif) + g = g->next; + g->next = hwif->next; + if (hwgroup->hwif == hwif) { + /* Chose a random hwif for hwgroup->hwif. + * It's guaranteed that there are no drives + * left in the hwgroup. + */ + BUG_ON(hwgroup->drive != NULL); + hwgroup->hwif = g; + } + BUG_ON(hwgroup->hwif == hwif); } - BUG_ON(hwgroup->hwif == hwif); } - - /* More messed up locking ... */ spin_unlock_irq(&ide_lock); - device_unregister(&hwif->gendev); - down(&hwif->gendev_rel_sem); + + /* + * PCI interfaces with no devices don't exist in the device + * tree so don't unregister them. + */ + + if(was_present) + { + device_unregister(&hwif->gendev); + down(&hwif->gendev_rel_sem); + } /* * Remove us from the kernel's knowledge @@ -907,6 +1060,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); @@ -918,6 +1078,7 @@ hwif->dma_vendor3 = 0; hwif->dma_prdtable = 0; } + hwif->chipset = ide_unknown; /* copy original settings */ tmp_hwif = *hwif; @@ -926,15 +1087,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 @@ -996,7 +1200,12 @@ * @fixup: fixup function * * Register an IDE interface, specifying exactly the registers etc. - * Set init=1 iff calling before probes have taken place. + * Set init=1 iff calling before probes have taken place. The + * ide_cfg_sem protects this against races. + * + * Invokes a fixup function after the probe and before device attachment + * that can be used by the driver to amend settings or to work around + * hardware funnies. * * Returns -1 on error. */ @@ -1006,6 +1215,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]; @@ -1016,28 +1227,36 @@ 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; } - for (index = 0; index < MAX_HWIFS; index++) - ide_unregister(index); + /* FIXME- this check should die as should the retry loop */ + for (index = 0; index < MAX_HWIFS; 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_with_fixup(hwif, fixup); @@ -1081,21 +1300,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) @@ -1119,10 +1338,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; @@ -1131,7 +1348,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 * @@ -1139,7 +1356,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; @@ -1217,7 +1434,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; @@ -1416,6 +1633,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 */ @@ -1428,6 +1646,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); } /** @@ -1484,28 +1704,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; @@ -1631,6 +1853,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))) @@ -1639,14 +1862,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; @@ -1672,9 +1899,13 @@ * spot if we miss one somehow */ - spin_lock_irqsave(&ide_lock, flags); - + + /* FIXME: need to block new commands here, must + find a better approach! */ + HWGROUP(drive)->busy = 1; DRIVER(drive)->abort(drive, "drive reset"); + + spin_lock_irqsave(&ide_lock, flags); if(HWGROUP(drive)->handler) BUG(); @@ -1895,10 +2126,10 @@ goto do_serialize; case -6: /* "autotune" */ drive->autotune = IDE_TUNE_AUTO; - goto obsolete_option; + goto done; case -7: /* "noautotune" */ drive->autotune = IDE_TUNE_NOAUTO; - goto obsolete_option; + goto done; case -9: /* "swapdata" */ case -10: /* "bswap" */ drive->bswap = 1; @@ -2030,30 +2261,30 @@ case -7: /* ata66 */ #ifdef CONFIG_BLK_DEV_IDEPCI hwif->udma_four = 1; - goto obsolete_option; + goto done; #else goto bad_hwif; #endif case -6: /* dma */ hwif->autodma = 1; - goto obsolete_option; + goto done; case -5: /* "reset" */ hwif->reset = 1; - goto obsolete_option; + goto done; case -4: /* "noautotune" */ hwif->drives[0].autotune = IDE_TUNE_NOAUTO; hwif->drives[1].autotune = IDE_TUNE_NOAUTO; - goto obsolete_option; + goto done; case -3: /* "autotune" */ hwif->drives[0].autotune = IDE_TUNE_AUTO; hwif->drives[1].autotune = IDE_TUNE_AUTO; - goto obsolete_option; + goto done; case -2: /* "serialize" */ do_serialize: hwif->mate = &ide_hwifs[hw^1]; hwif->mate->mate = hwif; hwif->serialized = hwif->mate->serialized = 1; - goto obsolete_option; + goto done; case -1: /* "noprobe" */ hwif->noprobe = 1; @@ -2070,7 +2301,7 @@ hwif->irq = vals[2]; hwif->noprobe = 0; hwif->chipset = ide_forced; - goto obsolete_option; + goto done; case 0: goto bad_option; default: @@ -2081,9 +2312,6 @@ bad_option: printk(" -- BAD OPTION\n"); return 1; -obsolete_option: - printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n"); - return 1; bad_hwif: printk("-- NOT SUPPORTED ON ide%d", hw); done: @@ -2271,8 +2499,8 @@ drive->suspend_reset = 0; #ifdef CONFIG_PROC_FS if (drive->driver != &idedefault_driver) { - ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - ide_add_proc_entries(drive->proc, driver->proc, drive); + ide_add_proc_entries(drive->proc, generic_subdriver_entries, ide_drive_to_key(drive)); + ide_add_proc_entries(drive->proc, driver->proc, ide_drive_to_key(drive)); } #endif return 0; @@ -2297,6 +2525,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); @@ -2305,13 +2534,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); @@ -2337,7 +2567,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) @@ -2348,9 +2579,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); @@ -2386,9 +2619,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); @@ -2502,7 +2737,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.10/drivers/ide/ide-cd.c linux-2.6.10/drivers/ide/ide-cd.c --- linux.vanilla-2.6.10/drivers/ide/ide-cd.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-cd.c 2005-01-06 21:57:14.000000000 +0000 @@ -366,7 +366,8 @@ * we cannot reliably check if drive can auto-close */ if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) - log = 0; + break; + log = 1; break; case UNIT_ATTENTION: /* @@ -388,6 +389,10 @@ struct request *failed_command, struct request_sense *sense) { + unsigned long sector; + unsigned long bio_sectors; + unsigned long valid; + if (!cdrom_log_sense(drive, failed_command, sense)) return; @@ -400,13 +405,43 @@ if (sense->sense_key == 0x05 && sense->asc == 0x24) return; + if (sense->error_code == 0x70) { /* Current Error */ + switch(sense->sense_key) { + case MEDIUM_ERROR: + case VOLUME_OVERFLOW: + case ILLEGAL_REQUEST: + if(!sense->valid) + break; + if(failed_command == NULL || !blk_fs_request(failed_command)) + break; + sector = (sense->information[0] << 24) | + (sense->information[1] << 16) | + (sense->information[2] << 8) | + (sense->information[3]); + + bio_sectors = bio_sectors(failed_command->bio); + if(bio_sectors < 4) + bio_sectors = 4; + if(drive->queue->hardsect_size == 2048) + sector <<= 2; /* Device sector size is 2K */ + sector &= ~(bio_sectors -1); + valid = (sector - failed_command->sector) << 9; + + if(valid < 0) + valid = 0; + if(sector < get_capacity(drive->disk) && + drive->probed_capacity - sector < 4 * 75) { + set_capacity(drive->disk, sector); + } + } + } #if VERBOSE_IDE_CD_ERRORS { int i; const char *s; char buf[80]; - printk ("ATAPI device %s:\n", drive->name); + printk (KERN_ERR "ATAPI device %s:\n", drive->name); if (sense->error_code==0x70) printk(" Error: "); else if (sense->error_code==0x71) @@ -456,7 +491,7 @@ s = "(reserved error code)"; } - printk(" %s -- (asc=0x%02x, ascq=0x%02x)\n", + printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n", s, sense->asc, sense->ascq); if (failed_command != NULL) { @@ -478,7 +513,7 @@ lo = mid+1; } - printk (" The failed \"%s\" packet command was: \n \"", s); + printk (KERN_ERR " The failed \"%s\" packet command was: \n \"", s); for (i=0; icmd); i++) printk ("%02x ", failed_command->cmd[i]); printk ("\"\n"); @@ -491,13 +526,13 @@ */ if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; - printk(" Command is %02d%% complete\n", progress / 0xffff); + printk(KERN_ERR " Command is %02d%% complete\n", progress / 0xffff); } if (sense->sense_key == ILLEGAL_REQUEST && (sense->sks[0] & 0x80) != 0) { - printk(" Error in %s byte %d", + printk(KERN_ERR " Error in %s byte %d", (sense->sks[0] & 0x40) != 0 ? "command packet" : "command data", (sense->sks[1] << 8) + sense->sks[2]); @@ -518,8 +553,8 @@ (sense->sense_key == NOT_READY && (sense->asc == 4 || sense->asc == 0x3a))) return; - - printk("%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", + + printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", drive->name, sense->error_code, sense->sense_key, sense->asc, sense->ascq); @@ -635,17 +670,22 @@ sense = failed->sense; failed->sense_len = rq->sense_len; } - + cdrom_analyze_sense_data(drive, failed, sense); /* * now end failed request */ - spin_lock_irqsave(&ide_lock, flags); - end_that_request_chunk(failed, 0, failed->data_len); - end_that_request_last(failed); - spin_unlock_irqrestore(&ide_lock, flags); + if(blk_fs_request(failed)) { + if(ide_end_dequeued_request(drive, failed, 0, failed->hard_nr_sectors)) + BUG(); + } else { + spin_lock_irqsave(&ide_lock, flags); + end_that_request_chunk(failed, 0, failed->data_len); + end_that_request_last(failed); + spin_unlock_irqrestore(&ide_lock, flags); + } } - - cdrom_analyze_sense_data(drive, failed, sense); + else + cdrom_analyze_sense_data(drive, NULL , sense); } if (!rq->current_nr_sectors && blk_fs_request(rq)) @@ -659,6 +699,13 @@ ide_end_request(drive, uptodate, nsectors); } +static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat) +{ + if(stat & 0x80) + return; + ide_dump_status(drive, msg, stat); +} + /* Returns 0 if the request should be continued. Returns 1 if the request was ended. */ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) @@ -787,16 +834,16 @@ sense_key == DATA_PROTECT) { /* No point in retrying after an illegal request or data protect error.*/ - ide_dump_status (drive, "command error", stat); + ide_dump_status_no_sense (drive, "command error", stat); do_end_request = 1; } else if (sense_key == MEDIUM_ERROR) { /* No point in re-trying a zillion times on a bad * sector... If we got here the error is not correctable */ - ide_dump_status (drive, "media error (bad sector)", stat); + ide_dump_status_no_sense (drive, "media error (bad sector)", stat); do_end_request = 1; } else if (sense_key == BLANK_CHECK) { /* Disk appears blank ?? */ - ide_dump_status (drive, "media error (blank)", stat); + ide_dump_status_no_sense (drive, "media error (blank)", stat); do_end_request = 1; } else if ((err & ~ABRT_ERR) != 0) { /* Go to the default handler @@ -808,13 +855,27 @@ do_end_request = 1; } - if (do_end_request) - cdrom_end_request(drive, 0); + /* End a request through request sense analysis when we have + sense data. We need this in order to perform end of media + processing */ + + if (do_end_request) { + if (stat & ERR_STAT) { + unsigned long flags; + spin_lock_irqsave(&ide_lock, flags); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + spin_unlock_irqrestore(&ide_lock, flags); - /* If we got a CHECK_CONDITION status, - queue a request sense command. */ - if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, NULL, NULL); + cdrom_queue_request_sense(drive, rq->sense, rq); + } + else cdrom_end_request(drive, 0); + } else { + /* If we got a CHECK_CONDITION status, + queue a request sense command. */ + if (stat & ERR_STAT) + cdrom_queue_request_sense(drive, NULL, NULL); + } } else { blk_dump_rq_flags(rq, "ide-cd: bad rq"); cdrom_end_request(drive, 0); @@ -872,7 +933,7 @@ return startstop; if (info->dma) - info->dma = !hwif->dma_setup(drive); + info->dma = !hwif->ide_dma_setup(drive); /* Set up the controller registers. */ /* FIXME: for Virtual DMA we must check harder */ @@ -948,7 +1009,7 @@ /* Start the DMA if need be */ if (info->dma) - hwif->dma_start(drive); + hwif->ide_dma_start(drive); return ide_started; } @@ -1014,7 +1075,7 @@ return 0; else if (ireason == 0) { /* Whoops... The drive is expecting to receive data from us! */ - printk("%s: read_intr: Drive wants to transfer data the " + printk(KERN_ERR "%s: read_intr: Drive wants to transfer data the " "wrong way!\n", drive->name); /* Throw some data at the drive so it doesn't hang @@ -1032,7 +1093,7 @@ return 0; } else { /* Drive wants a command packet, or invalid ireason... */ - printk("%s: read_intr: bad interrupt reason %x\n", drive->name, + printk(KERN_ERR "%s: read_intr: bad interrupt reason %x\n", drive->name, ireason); } @@ -1085,7 +1146,7 @@ /* If we're not done filling the current buffer, complain. Otherwise, complete the command normally. */ if (rq->current_nr_sectors > 0) { - printk ("%s: cdrom_read_intr: data underrun (%d blocks)\n", + printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n", drive->name, rq->current_nr_sectors); rq->flags |= REQ_FAILED; cdrom_end_request(drive, 0); @@ -1102,12 +1163,12 @@ of at least SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */ if ((len % SECTOR_SIZE) != 0) { - printk ("%s: cdrom_read_intr: Bad transfer size %d\n", + printk (KERN_ERR "%s: cdrom_read_intr: Bad transfer size %d\n", drive->name, len); if (CDROM_CONFIG_FLAGS(drive)->limit_nframes) - printk (" This drive is not supported by this version of the driver\n"); + printk (KERN_ERR " This drive is not supported by this version of the driver\n"); else { - printk (" Trying to limit transfer sizes\n"); + printk (KERN_ERR " Trying to limit transfer sizes\n"); CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1; } cdrom_end_request(drive, 0); @@ -1221,7 +1282,7 @@ paranoid and check. */ if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) && (rq->sector & (sectors_per_frame - 1))) { - printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n", + printk(KERN_ERR "%s: cdrom_read_from_buffer: buffer botch (%ld)\n", drive->name, (long)rq->sector); cdrom_end_request(drive, 0); return -1; @@ -1256,7 +1317,7 @@ /* Sanity check... */ if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) && (rq->sector & (sectors_per_frame - 1))) { - printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n", + printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n", drive->name, rq->current_nr_sectors); cdrom_end_request(drive, 0); return ide_stopped; @@ -1481,7 +1542,7 @@ rq->sense_len += thislen; } else { confused: - printk ("%s: cdrom_pc_intr: The drive " + printk (KERN_ERR "%s: cdrom_pc_intr: The drive " "appears confused (ireason = 0x%02x)\n", drive->name, ireason); rq->flags |= REQ_FAILED; @@ -1520,21 +1581,7 @@ } -/* Sleep for TIME jiffies. - Not to be called from an interrupt handler. */ -static -void cdrom_sleep (int time) -{ - int sleep = time; - - do { - set_current_state(TASK_INTERRUPTIBLE); - sleep = schedule_timeout(sleep); - } while (sleep); -} - -static -int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) +static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) { struct request_sense sense; int retries = 10; @@ -1567,7 +1614,7 @@ /* The drive is in the process of loading a disk. Retry, but wait a little to give the drive time to complete the load. */ - cdrom_sleep(2 * HZ); + msleep(2000); } else { /* Otherwise, don't retry. */ retries = 0; @@ -1595,7 +1642,7 @@ return 0; else if (ireason == 2) { /* Whoops... The drive wants to send data. */ - printk("%s: write_intr: wrong transfer direction!\n", + printk(KERN_ERR "%s: write_intr: wrong transfer direction!\n", drive->name); while (len > 0) { @@ -1605,7 +1652,7 @@ } } else { /* Drive wants a command packet, or invalid ireason... */ - printk("%s: write_intr: bad interrupt reason %x\n", + printk(KERN_ERR "%s: write_intr: bad interrupt reason %x\n", drive->name, ireason); } @@ -1671,7 +1718,7 @@ */ if (dma) { if (dma_error) { - printk("ide-cd: dma error\n"); + printk(KERN_ERR "ide-cd: dma error\n"); __ide_dma_off(drive); return DRIVER(drive)->error(drive, "dma error", stat); } @@ -1736,7 +1783,7 @@ } if (!ptr) { - printk("%s: confused, missing data\n", drive->name); + printk(KERN_ERR "%s: confused, missing data\n", drive->name); break; } @@ -1798,7 +1845,7 @@ if (dma) { info->dma = 0; if ((dma_error = HWIF(drive)->ide_dma_end(drive))) { - printk("ide-cd: write dma error\n"); + printk(KERN_ERR "ide-cd: write dma error\n"); __ide_dma_off(drive); } } @@ -1831,7 +1878,7 @@ */ uptodate = 1; if (rq->current_nr_sectors > 0) { - printk("%s: write_intr: data underrun (%d blocks)\n", + printk(KERN_ERR "%s: write_intr: data underrun (%d blocks)\n", drive->name, rq->current_nr_sectors); uptodate = 0; } @@ -1852,7 +1899,7 @@ int this_transfer; if (!rq->current_nr_sectors) { - printk("ide-cd: write_intr: oops\n"); + printk(KERN_ERR "ide-cd: write_intr: oops\n"); break; } @@ -1998,7 +2045,7 @@ ide_stall_queue(drive, IDECD_SEEK_TIMER); return ide_stopped; } - printk ("%s: DSC timeout\n", drive->name); + printk (KERN_ERR "%s: DSC timeout\n", drive->name); } CDROM_CONFIG_FLAGS(drive)->seeking = 0; } @@ -2134,7 +2181,7 @@ if (stat != 0 && sense->sense_key == ILLEGAL_REQUEST && (sense->asc == 0x24 || sense->asc == 0x20)) { - printk ("%s: door locking not supported\n", + printk (KERN_ERR "%s: door locking not supported\n", drive->name); CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; stat = 0; @@ -2252,7 +2299,7 @@ GFP_KERNEL); info->toc = toc; if (toc == NULL) { - printk ("%s: No cdrom TOC buffer!\n", drive->name); + printk (KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name); return -ENOMEM; } } @@ -2271,6 +2318,9 @@ toc->capacity = 0x1fffff; set_capacity(drive->disk, toc->capacity * sectors_per_frame); + /* Save a private copy of te TOC capacity for error handling */ + drive->probed_capacity = toc->capacity * sectors_per_frame; + blk_queue_hardsect_size(drive->queue, sectors_per_frame << SECTOR_BITS); @@ -2391,6 +2441,7 @@ if (!stat && (last_written > toc->capacity)) { toc->capacity = last_written; set_capacity(drive->disk, toc->capacity * sectors_per_frame); + drive->probed_capacity = toc->capacity * sectors_per_frame; } /* Remember that we've read this stuff. */ @@ -2743,12 +2794,10 @@ * any other way to detect this... */ if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a) { - if (sense.ascq == 0 || sense.ascq == 1) - return CDS_NO_DISC; - else if (sense.ascq == 2) - return CDS_TRAY_OPEN; - } + if (sense.asc == 0x3a && sense.ascq == 1) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; } return CDS_DRIVE_NOT_READY; @@ -2939,7 +2988,7 @@ if (drive->media == ide_optical) { CDROM_CONFIG_FLAGS(drive)->mo_drive = 1; CDROM_CONFIG_FLAGS(drive)->ram = 1; - printk("%s: ATAPI magneto-optical drive\n", drive->name); + printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name); return nslots; } @@ -3029,7 +3078,7 @@ /* don't print speed if the drive reported 0. */ - printk("%s: ATAPI", drive->name); + printk(KERN_INFO "%s: ATAPI", drive->name); if (CDROM_CONFIG_FLAGS(drive)->max_speed) printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed); printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM"); @@ -3272,7 +3321,7 @@ #endif if (ide_cdrom_register(drive, nslots)) { - printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); + printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); info->devinfo.handle = NULL; return 1; } @@ -3299,7 +3348,7 @@ struct gendisk *g = drive->disk; if (ide_unregister_subdriver(drive)) { - printk("%s: %s: failed to ide_unregister_subdriver\n", + printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n", __FUNCTION__, drive->name); return 1; } @@ -3310,7 +3359,7 @@ if (info->changer_info != NULL) kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom(devinfo)) - printk("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); + printk(KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree(info); drive->driver_data = NULL; blk_queue_prep_rq(drive->queue, NULL); @@ -3462,21 +3511,21 @@ /* skip drives that we were told to ignore */ if (ignore != NULL) { if (strstr(ignore, drive->name)) { - printk("ide-cd: ignoring drive %s\n", drive->name); + printk(KERN_INFO "ide-cd: ignoring drive %s\n", drive->name); goto failed; } } if (drive->scsi) { - printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); + printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); goto failed; } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { - printk("%s: Can't allocate a cdrom structure\n", drive->name); + printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name); goto failed; } if (ide_register_subdriver(drive, &ide_cdrom_driver)) { - printk("%s: Failed to register the driver with ide.c\n", + printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name); kfree(info); goto failed; @@ -3500,7 +3549,7 @@ if (info->changer_info != NULL) kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom(devinfo)) - printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); + printk (KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree(info); drive->driver_data = NULL; goto failed; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-disk.c linux-2.6.10/drivers/ide/ide-disk.c --- linux.vanilla-2.6.10/drivers/ide/ide-disk.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-disk.c 2004-12-29 22:32:59.000000000 +0000 @@ -84,6 +84,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. @@ -211,7 +215,7 @@ } if (dma) { - if (!hwif->dma_setup(drive)) { + if (!hwif->ide_dma_setup(drive)) { if (rq_data_dir(rq)) { command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; if (drive->vdma) @@ -221,8 +225,8 @@ if (drive->vdma) command = lba48 ? WIN_READ_EXT: WIN_READ; } - hwif->dma_exec_cmd(drive, command); - hwif->dma_start(drive); + hwif->ide_dma_exec_cmd(drive, command); + hwif->ide_dma_start(drive); return ide_started; } /* fallback to PIO */ @@ -624,13 +628,14 @@ static inline void idedisk_check_hpa(ide_drive_t *drive) { - unsigned long long capacity, set_max; + unsigned long long capacity, set_max = 0; int lba48 = idedisk_supports_lba48(drive->id); + capacity = drive->capacity64; if (lba48) set_max = idedisk_read_native_max_address_ext(drive); - else + if (set_max == 0) /* LBA28 or LBA48 failed */ set_max = idedisk_read_native_max_address(drive); if (set_max <= capacity) @@ -643,7 +648,8 @@ capacity, sectors_to_MB(capacity), set_max, sectors_to_MB(set_max)); - if (lba48) + /* Some maxtor support LBA48 but do not accept LBA48 set max... */ + if (lba48 || set_max < (1ULL << 28)) set_max = idedisk_set_max_address_ext(drive, set_max); else set_max = idedisk_set_max_address(drive, set_max); @@ -821,24 +827,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; @@ -848,16 +860,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; @@ -867,6 +883,7 @@ } while (i < (SECTOR_WORDS * 2)); len = out - page; } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -1239,8 +1256,9 @@ 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) ide_dma_verbose(drive); printk("\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-dma.c linux-2.6.10/drivers/ide/ide-dma.c --- linux.vanilla-2.6.10/drivers/ide/ide-dma.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-dma.c 2004-12-26 22:15:32.000000000 +0000 @@ -927,12 +927,12 @@ hwif->ide_dma_host_on = &__ide_dma_host_on; if (!hwif->ide_dma_check) hwif->ide_dma_check = &__ide_dma_check; - if (!hwif->dma_setup) - hwif->dma_setup = &ide_dma_setup; - if (!hwif->dma_exec_cmd) - hwif->dma_exec_cmd = &ide_dma_exec_cmd; - if (!hwif->dma_start) - hwif->dma_start = &ide_dma_start; + if (!hwif->ide_dma_setup) + hwif->ide_dma_setup = &ide_dma_setup; + if (!hwif->ide_dma_exec_cmd) + hwif->ide_dma_exec_cmd = &ide_dma_exec_cmd; + if (!hwif->ide_dma_start) + hwif->ide_dma_start = &ide_dma_start; if (!hwif->ide_dma_end) hwif->ide_dma_end = &__ide_dma_end; if (!hwif->ide_dma_test_irq) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-floppy.c linux-2.6.10/drivers/ide/ide-floppy.c --- linux.vanilla-2.6.10/drivers/ide/ide-floppy.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-floppy.c 2004-12-26 21:54:53.000000000 +0000 @@ -1066,7 +1066,7 @@ feature.all = 0; if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - feature.b.dma = !hwif->dma_setup(drive); + feature.b.dma = !hwif->ide_dma_setup(drive); if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); @@ -1078,7 +1078,7 @@ if (feature.b.dma) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); - hwif->dma_start(drive); + hwif->ide_dma_start(drive); } /* Can we transfer the packet when we get the interrupt or wait? */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-io.c linux-2.6.10/drivers/ide/ide-io.c --- linux.vanilla-2.6.10/drivers/ide/ide-io.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-io.c 2005-01-04 21:15:39.000000000 +0000 @@ -190,6 +190,62 @@ EXPORT_SYMBOL(ide_end_request); /** + * ide_end_dequeued_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * Complete an I/O that is no longer on the request queue. This + * typically occurs when we pull the request and issue a REQUEST_SENSE. + * We must still finish the old request but we must not tamper with the + * queue in the meantime. + * + * NOTE: This path does not handle barrier, but barrier is not supported + * on ide-cd anyway. + */ + +int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + + BUG_ON(!(rq->flags & REQ_STARTED)); + + /* + * if failfast is set on a request, override number of sectors and + * complete the whole request right now + */ + if (blk_noretry_request(rq) && end_io_error(uptodate)) + nr_sectors = rq->hard_nr_sectors; + + if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + rq->errors = -EIO; + + /* + * decide whether to reenable DMA -- 3 is a random magic for now, + * if we DMA timeout more than 3 times, just stay in PIO + */ + if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { + drive->state = 0; + HWGROUP(drive)->hwif->ide_dma_on(drive); + } + + if (!end_that_request_first(rq, uptodate, nr_sectors)) { + add_disk_randomness(rq->rq_disk); + if (blk_rq_tagged(rq)) + blk_queue_end_tag(drive->queue, rq); + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ide_end_dequeued_request); + +/** * ide_complete_pm_request - end the current Power Management request * @drive: target drive * @rq: request @@ -555,30 +611,38 @@ * This differs fundamentally from ide_error because in * this case the command is doing just fine when we * blow it away. + * + * FIXME: need to fix locking corner cases */ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg) { ide_hwif_t *hwif; struct request *rq; + unsigned long flags; - if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + spin_lock_irqsave(&ide_lock, flags); + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) { + spin_unlock_irqrestore(&ide_lock, flags); return ide_stopped; - + } hwif = HWIF(drive); /* retry only "normal" I/O: */ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { rq->errors = 1; + spin_unlock_irqrestore(&ide_lock, flags); ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } if (rq->flags & REQ_DRIVE_TASKFILE) { rq->errors = 1; + spin_unlock_irqrestore(&ide_lock, flags); ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } rq->errors |= ERROR_RESET; + spin_unlock_irqrestore(&ide_lock, flags); DRIVER(drive)->end_request(drive, 0, 0); return ide_stopped; } @@ -1212,7 +1276,7 @@ rq->sector = rq->bio->bi_sector; rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; rq->hard_cur_sectors = rq->current_nr_sectors; - rq->buffer = NULL; + rq->buffer = bio_data(rq->bio); out: return ret; } @@ -1419,6 +1483,13 @@ return IRQ_NONE; } + if (hwif->polling) { + /* We took an interrupt during a polled drive retune. + This should go away eventually when that code uses + the polling logic like do_reset1 */ + spin_unlock_irqrestore(&ide_lock, flags); + return IRQ_HANDLED; + } if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) { /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-iops.c linux-2.6.10/drivers/ide/ide-iops.c --- linux.vanilla-2.6.10/drivers/ide/ide-iops.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-iops.c 2004-12-26 19:10:52.000000000 +0000 @@ -107,6 +107,74 @@ EXPORT_SYMBOL(default_hwif_iops); /* + * Interface removed + */ + +static u8 ide_no_inb(unsigned long port) +{ + return 0xFF; +} + +static u16 ide_no_inw (unsigned long port) +{ + return 0xFFFF; +} + +static void ide_no_insw (unsigned long port, void *addr, u32 count) +{ +} + +static u32 ide_no_inl (unsigned long port) +{ + return 0xFFFFFFFF; +} + +static void ide_no_insl (unsigned long port, void *addr, u32 count) +{ +} + +static void ide_no_outb (u8 val, unsigned long port) +{ +} + +static void ide_no_outbsync (ide_drive_t *drive, u8 addr, unsigned long port) +{ +} + +static void ide_no_outw (u16 val, unsigned long port) +{ +} + +static void ide_no_outsw (unsigned long port, void *addr, u32 count) +{ +} + +static void ide_no_outl (u32 val, unsigned long port) +{ +} + +static void ide_no_outsl (unsigned long port, void *addr, u32 count) +{ +} + +void removed_hwif_iops (ide_hwif_t *hwif) +{ + hwif->OUTB = ide_no_outb; + hwif->OUTBSYNC = ide_no_outbsync; + hwif->OUTW = ide_no_outw; + hwif->OUTL = ide_no_outl; + hwif->OUTSW = ide_no_outsw; + hwif->OUTSL = ide_no_outsl; + hwif->INB = ide_no_inb; + hwif->INW = ide_no_inw; + hwif->INL = ide_no_inl; + hwif->INSW = ide_no_insw; + hwif->INSL = ide_no_insl; +} + +EXPORT_SYMBOL(removed_hwif_iops); + +/* * MMIO operations, typically used for SATA controllers */ @@ -606,44 +674,15 @@ */ u8 eighty_ninty_three (ide_drive_t *drive) { -#if 0 - if (!HWIF(drive)->udma_four) + if(HWIF(drive)->udma_four == 0) + return 0; + if (!(drive->id->hw_config & 0x6000)) return 0; - - if (drive->id->major_rev_num) { - int hssbd = 0; - int i; - /* - * Determine highest Supported SPEC - */ - for (i=1; i<=15; i++) - if (drive->id->major_rev_num & (1<id->hw_config & 0x4000) && -#endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); - -#else - - return ((u8) ((HWIF(drive)->udma_four) && #ifndef CONFIG_IDEDMA_IVB - (drive->id->hw_config & 0x4000) && + if(!(drive->id->hw_config & 0x4000)) + return 0; #endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); -#endif + return 1; } EXPORT_SYMBOL(eighty_ninty_three); @@ -801,6 +840,11 @@ * It is gone.......... * * const char *msg == consider adding for verbose errors. + * + * Beware. If we timed out from a series of CRC errors and the timer + * expiry caused a switch to PIO mode and we take an IRQ as the drive times + * out about the same moment we may be entering this function with a + * pending interrupt. */ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) { @@ -818,20 +862,20 @@ /* * Don't use ide_wait_cmd here - it will - * attempt to set_geometry and recalibrate, - * but for some reason these don't work at - * this point (lost interrupt). - */ - /* - * Select the drive, and issue the SETFEATURES command + * attempt to set_geometry and recalibrate, We can't + * do that here as we may be in the IRQ handler already + * + * Select the drive, and issue the SETFEATURES command in + * polled mode. */ disable_irq_nosync(hwif->irq); /* - * FIXME: we race against the running IRQ here if + * We race against the running IRQ here if * this is called from non IRQ context. If we use - * disable_irq() we hang on the error path. Work - * is needed. + * disable_irq() we hang on the error path. Instead we + * must let the core code know the hwif is doing a polling + * recovery. */ udelay(1); @@ -842,23 +886,43 @@ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); hwif->OUTB(speed, IDE_NSECTOR_REG); hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG); - hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG); - if ((IDE_CONTROL_REG) && (drive->quirk_list == 2)) + hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); + /* The status bits are not valid for 400nS */ + udelay(1); + + /* Drive status is now valid which means we can allow interrupts + to occur as they will see the drive as busy and will not + interfere erroneously. IRQ's for this drive will also be off + providing control and quirks allow for it */ + + if ((IDE_CONTROL_REG) && drive->quirk_list == 2) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); udelay(1); + + /* + * Tell the interrupt layer that we are doing polled recovery. + * Eventually this should use the same mechanism do_reset does + * internally. + */ + + hwif->polling = 1; + /* * Wait for drive to become non-BUSY */ if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { - unsigned long flags, timeout; - local_irq_set(flags); + unsigned long timeout; + /* FIXME */ +/* spin_unlock_irq(&ide_lock); */ timeout = jiffies + WAIT_CMD; while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { if (time_after(jiffies, timeout)) break; } - local_irq_restore(flags); +/* spin_lock_irq(&ide_lock); */ } + + hwif->polling = 0; /* * Allow status to settle, then read it again. @@ -1168,7 +1232,8 @@ pre_reset(drive); SELECT_DRIVE(drive); udelay (20); - hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); + hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG); + ndelay(400); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL); spin_unlock_irqrestore(&ide_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-pnp.c linux-2.6.10/drivers/ide/ide-pnp.c --- linux.vanilla-2.6.10/drivers/ide/ide-pnp.c 2004-12-25 21:14:31.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-pnp.c 2005-01-07 15:02:52.000000000 +0000 @@ -19,6 +19,7 @@ #include #include #include +#include /* Add your devices here :)) */ struct pnp_device_id idepnp_devices[] = { @@ -57,7 +58,11 @@ { ide_hwif_t *hwif = pnp_get_drvdata(dev); if (hwif) { - ide_unregister(hwif->index); + /* FIXME: will want pushing into a helper workqueue */ + while(ide_unregister_hwif(hwif) < 0) { + removed_hwif_iops(hwif); + msleep(1000); + } } 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.10/drivers/ide/ide-probe.c linux-2.6.10/drivers/ide/ide-probe.c --- linux.vanilla-2.6.10/drivers/ide/ide-probe.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-probe.c 2004-12-26 21:09:22.000000000 +0000 @@ -614,6 +614,7 @@ } hwif->gendev.release = hwif_release_dev; device_register(&hwif->gendev); + hwif->configured = 1; } static int wait_hwif_ready(ide_hwif_t *hwif) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-proc.c linux-2.6.10/drivers/ide/ide-proc.c --- linux.vanilla-2.6.10/drivers/ide/ide-proc.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-proc.c 2004-12-26 21:24:43.000000000 +0000 @@ -42,68 +42,86 @@ 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_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_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; @@ -121,6 +139,7 @@ len = out - page; } } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -139,13 +158,22 @@ 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; proc_ide_settings_warn(); + 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"); @@ -172,10 +200,10 @@ #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; @@ -184,6 +212,9 @@ if (!capable(CAP_SYS_ADMIN)) return -EACCES; + + if (drive == NULL) + return -EIO; proc_ide_settings_warn(); @@ -266,30 +297,55 @@ 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; + 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); out += sprintf(out,"logical %d/%d/%d\n", 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); } @@ -298,52 +354,60 @@ 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; @@ -358,11 +422,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 }, @@ -414,7 +479,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; @@ -465,7 +530,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); } @@ -492,6 +557,8 @@ } } +EXPORT_SYMBOL(destroy_proc_ide_interface); + static void destroy_proc_ide_interfaces(void) { int h; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-tape.c linux-2.6.10/drivers/ide/ide-tape.c --- linux.vanilla-2.6.10/drivers/ide/ide-tape.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-tape.c 2004-12-26 21:55:18.000000000 +0000 @@ -2067,7 +2067,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA /* Begin DMA, if necessary */ if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) - hwif->dma_start(drive); + hwif->ide_dma_start(drive); #endif /* Send the actual packet */ HWIF(drive)->atapi_output_bytes(drive, pc->c, 12); @@ -2136,7 +2136,7 @@ (void)__ide_dma_off(drive); } if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - dma_ok = !hwif->dma_setup(drive); + dma_ok = !hwif->ide_dma_setup(drive); if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ide-taskfile.c linux-2.6.10/drivers/ide/ide-taskfile.c --- linux.vanilla-2.6.10/drivers/ide/ide-taskfile.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ide-taskfile.c 2004-12-26 22:46:31.000000000 +0000 @@ -147,9 +147,9 @@ case WIN_READDMA: case WIN_READDMA_EXT: case WIN_IDENTIFY_DMA: - if (!hwif->dma_setup(drive)) { - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); + if (!hwif->ide_dma_setup(drive)) { + hwif->ide_dma_exec_cmd(drive, taskfile->command); + hwif->ide_dma_start(drive); return ide_started; } break; @@ -863,9 +863,9 @@ case TASKFILE_OUT_DMA: case TASKFILE_IN_DMAQ: case TASKFILE_IN_DMA: - hwif->dma_setup(drive); - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); + hwif->ide_dma_setup(drive); + hwif->ide_dma_exec_cmd(drive, taskfile->command); + hwif->ide_dma_start(drive); break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/Kconfig linux-2.6.10/drivers/ide/Kconfig --- linux.vanilla-2.6.10/drivers/ide/Kconfig 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/Kconfig 2004-12-29 23:05:30.000000000 +0000 @@ -166,6 +166,13 @@ Support for outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. +config BLK_DEV_DELKIN + tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" + depends on PCMCIA && PCI + help + Support for Delkin, ASKA, and Workbit Cardbus CompactFlash + Adapters. This may also work for similar SD and XD adapters. + config BLK_DEV_IDECD tristate "Include IDE/ATAPI CDROM support" ---help--- @@ -607,6 +614,12 @@ ; picture of the board at . +config BLK_DEV_IT821X + tristate "IT821X IDE support" + help + This driver adds support for the ITE 8211 IDE controller and the + IT 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.10/drivers/ide/legacy/ide-cs.c linux-2.6.10/drivers/ide/legacy/ide-cs.c --- linux.vanilla-2.6.10/drivers/ide/legacy/ide-cs.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/legacy/ide-cs.c 2005-01-04 15:15:20.000000000 +0000 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -90,6 +91,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 +201,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_with_fixup(&hw, NULL, ide_undecoded_slave); + return ide_register_hw_with_fixup(&hw, hwif, ide_undecoded_slave); } /*====================================================================== @@ -224,6 +226,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,22 +346,24 @@ 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; break; } } - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); } if (hd < 0) { @@ -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, @@ -409,9 +415,11 @@ DEBUG(0, "ide_release(0x%p)\n", link); 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); + /* Wait for the interface to cease to be busy */ + while(ide_unregister_hwif(info->hwif) < 0) { + removed_hwif_iops(info->hwif); + msleep(1000); + } } info->ndev = 0; link->dev = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/alim15x3.c linux-2.6.10/drivers/ide/pci/alim15x3.c --- linux.vanilla-2.6.10/drivers/ide/pci/alim15x3.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/alim15x3.c 2004-12-26 21:51:46.000000000 +0000 @@ -775,7 +775,7 @@ * M1543C or newer for DMAing */ hwif->ide_dma_check = &ali15x3_config_drive_for_dma; - hwif->dma_setup = &ali15x3_dma_setup; + hwif->ide_dma_setup = &ali15x3_dma_setup; if (!noautodma) hwif->autodma = 1; if (!(hwif->udma_four)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/atiixp.c linux-2.6.10/drivers/ide/pci/atiixp.c --- linux.vanilla-2.6.10/drivers/ide/pci/atiixp.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/atiixp.c 2004-12-26 21:12:36.000000000 +0000 @@ -347,7 +347,9 @@ static struct pci_device_id atiixp_pci_tbl[] = { { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/cs5520.c linux-2.6.10/drivers/ide/pci/cs5520.c --- linux.vanilla-2.6.10/drivers/ide/pci/cs5520.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/cs5520.c 2004-12-26 22:05:06.000000000 +0000 @@ -158,10 +158,11 @@ * DMA channel */ -static int cs5520_dma_on(ide_drive_t *drive) +static int cs5520_dma_setup(ide_drive_t *drive) { - drive->vdma = 1; - return 0; + /* If DMA setup works then VDMA on */ + drive->vdma = ide_dma_setup(drive) ? 1: 0; + return drive->vdma; } static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) @@ -169,7 +170,7 @@ hwif->tuneproc = &cs5520_tune_drive; hwif->speedproc = &cs5520_tune_chipset; hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; - hwif->ide_dma_on = &cs5520_dma_on; + hwif->ide_dma_setup = &cs5520_dma_setup; if(!noautodma) hwif->autodma = 1; @@ -224,7 +225,7 @@ if(pci_enable_device_bars(dev, 1<<2)) { printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); - return 1; + return -EBUSY; } pci_set_master(dev); if (pci_set_dma_mask(dev, 0xFFFFFFFF)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/delkin_cb.c linux-2.6.10/drivers/ide/pci/delkin_cb.c --- linux.vanilla-2.6.10/drivers/ide/pci/delkin_cb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/ide/pci/delkin_cb.c 2004-12-26 18:49:59.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * linux/drivers/ide/pci/delkin_cb.c + * + * Created 20 Oct 2004 by Mark Lord + * + * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter + * + * Modeled after the 16-bit PCMCIA driver: ide-cs.c + * + * This is slightly peculiar, in that it is a PCI driver, + * but is NOT an IDE PCI driver -- the IDE layer does not directly + * support hot insertion/removal of PCI interfaces, so this driver + * is unable to use the IDE PCI interfaces. Instead, it uses the + * same interfaces as the ide-cs (PCMCIA) driver uses. + * On the plus side, the driver is also smaller/simpler this way. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No chip documentation has yet been found, + * so these configuration values were pulled from + * a running Win98 system using "debug". + * This gives around 3MByte/second read performance, + * which is about 2/3 of what the chip is capable of. + * + * There is also a 4KByte mmio region on the card, + * but its purpose has yet to be reverse-engineered. + */ +static const u8 setup[] = { + 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, + 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, +}; + +static int __devinit +delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned long base; + hw_regs_t hw; + ide_hwif_t *hwif = NULL; + ide_drive_t *drive; + int i, rc; + + rc = pci_enable_device(dev); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); + return rc; + } + rc = pci_request_regions(dev, "delkin_cb"); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); + pci_disable_device(dev); + return rc; + } + base = pci_resource_start(dev, 0); + outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ + inb(base + 0x17); /* read status to clear interrupts */ + for (i = 0; i < sizeof(setup); ++i) { + if (setup[i]) + outb(setup[i], base + i); + } + pci_release_regions(dev); /* IDE layer handles regions itself */ + + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, base + 0x10, base + 0x1e); + hw.irq = dev->irq; + hw.chipset = ide_pci; /* this enables IRQ sharing */ + + rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave); + if (rc < 0) { + printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc); + pci_disable_device(dev); + return -ENODEV; + } + pci_set_drvdata(dev, hwif); + hwif->pci_dev = dev; + drive = &hwif->drives[0]; + if (drive->present) { + drive->io_32bit = 1; + drive->unmask = 1; + } + return 0; +} + +static void +delkin_cb_remove (struct pci_dev *dev) +{ + ide_hwif_t *hwif = pci_get_drvdata(dev); + + if (hwif) + ide_unregister_hwif(hwif); + pci_disable_device(dev); +} + +static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_WORKBIT, PCI_DEVICE_ID_WORKBIT_CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); + +static struct pci_driver driver = { + .name = "Delkin/ASKA/Workbit Cardbus IDE", + .id_table = delkin_cb_pci_tbl, + .probe = delkin_cb_probe, + .remove = delkin_cb_remove, +}; + +static int +delkin_cb_init (void) +{ + return pci_module_init(&driver); +} + +static void +delkin_cb_exit (void) +{ + pci_unregister_driver(&driver); +} + +module_init(delkin_cb_init); +module_exit(delkin_cb_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); +MODULE_LICENSE("GPL"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/generic.c linux-2.6.10/drivers/ide/pci/generic.c --- linux.vanilla-2.6.10/drivers/ide/pci/generic.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/generic.c 2004-12-28 23:43:59.000000000 +0000 @@ -41,6 +41,17 @@ #include "generic.h" +static int ide_generic_all; /* Set to claim all devices */ + +static int __init ide_generic_all_on(char *unused) +{ + ide_generic_all = 1; + printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n"); + return 1; +} + +__setup("all-generic-ide", ide_generic_all_on); + static unsigned int __devinit init_chipset_generic (struct pci_dev *dev, const char *name) { return 0; @@ -96,43 +107,54 @@ { ide_pci_device_t *d = &generic_chipsets[id->driver_data]; u16 command; + + /* Don't use the generic entry unless instructed to do so */ + if (id->driver_data == 0) + if(ide_generic_all == 0) + return -ENODEV; if (dev->vendor == PCI_VENDOR_ID_UMC && dev->device == PCI_DEVICE_ID_UMC_UM8886A && (!(PCI_FUNC(dev->devfn) & 1))) - return 1; /* UM8886A/BF pair */ + return -EAGAIN; /* UM8886A/BF pair */ if (dev->vendor == PCI_VENDOR_ID_OPTI && dev->device == PCI_DEVICE_ID_OPTI_82C558 && (!(PCI_FUNC(dev->devfn) & 1))) - return 1; + return -EAGAIN; pci_read_config_word(dev, PCI_COMMAND, &command); - if(!(command & PCI_COMMAND_IO)) - { + if(!(command & PCI_COMMAND_IO)) { printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name); - return 1; + return -ENODEV; } ide_setup_pci_device(dev, d); return 0; } +static void __devexit generic_remove_one(struct pci_dev *dev) +{ + ide_pci_remove_hwifs(dev); +} + static struct pci_device_id generic_pci_tbl[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, + { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, #ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, #endif - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, + /* Must come last. If you add entries adjust this table appropriately and the init_one code */ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, generic_pci_tbl); @@ -141,6 +163,7 @@ .name = "PCI_IDE", .id_table = generic_pci_tbl, .probe = generic_init_one, + .remove = generic_remove_one, }; static int generic_ide_init(void) @@ -150,6 +173,14 @@ module_init(generic_ide_init); +static void generic_ide_exit(void) +{ + return ide_pci_unregister_driver(&driver); +} + +module_exit(generic_ide_exit); + + MODULE_AUTHOR("Andre Hedrick"); MODULE_DESCRIPTION("PCI driver module for generic PCI IDE"); MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/generic.h linux-2.6.10/drivers/ide/pci/generic.h --- linux.vanilla-2.6.10/drivers/ide/pci/generic.h 2004-12-25 21:14:31.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/generic.h 2004-12-26 17:22:58.000000000 +0000 @@ -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.10/drivers/ide/pci/hpt366.c linux-2.6.10/drivers/ide/pci/hpt366.c --- linux.vanilla-2.6.10/drivers/ide/pci/hpt366.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/hpt366.c 2004-12-26 22:07:35.000000000 +0000 @@ -10,6 +10,11 @@ * donation of an ABit BP6 mainboard, processor, and memory acellerated * development and support. * + * + * Highpoint have their own driver (source except for the raid part) + * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz + * This may be useful to anyone wanting to work on the mainstream hpt IDE. + * * Note that final HPT370 support was done by force extraction of GPL. * * - add function for getting/setting power status of drive @@ -108,6 +113,12 @@ } #endif +/* + * 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; @@ -405,7 +416,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); @@ -497,7 +512,7 @@ /* how about we flush and reset, mmmkay? */ pci_write_config_byte(dev, 0x51, 0x1F); /* fall through to a reset */ - case dma_start: + case ide_dma_start: case ide_dma_end: /* reset the chips state over and over.. */ pci_write_config_byte(dev, 0x51, 0x13); @@ -806,7 +821,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); @@ -901,6 +920,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; @@ -950,6 +972,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); @@ -1141,7 +1166,7 @@ hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; hwif->ide_dma_end = &hpt374_ide_dma_end; } else if (hpt_minimum_revision(dev,3)) { - hwif->dma_start = &hpt370_ide_dma_start; + hwif->ide_dma_start = &hpt370_ide_dma_start; hwif->ide_dma_end = &hpt370_ide_dma_end; hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/it8172.c linux-2.6.10/drivers/ide/pci/it8172.c --- linux.vanilla-2.6.10/drivers/ide/pci/it8172.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/it8172.c 2004-12-26 17:22:17.000000000 +0000 @@ -270,7 +270,7 @@ { if ((!(PCI_FUNC(dev->devfn) & 1) || (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))) - return 1; /* IT8172 is more than only a IDE controller */ + return -EAGAIN; /* IT8172 is more than only a IDE controller */ ide_setup_pci_device(dev, &it8172_chipsets[id->driver_data]); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/it821x.c linux-2.6.10/drivers/ide/pci/it821x.c --- linux.vanilla-2.6.10/drivers/ide/pci/it821x.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/ide/pci/it821x.c 2005-01-06 21:39:58.000000000 +0000 @@ -0,0 +1,812 @@ + +/* + * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004 + * + * Copyright (C) 2004 Red Hat + * + * May be copied or modified under the terms of the GNU General Public License + * Based in part on the ITE vendor provided SCSI driver. + * + * Documentation available from + * http://www.ite.com.tw/pc/IT8212F_V04.pdf + * Some other documents are NDA. + * + * The ITE8212 isn't exactly a standard IDE controller. It has two + * modes. In pass through mode then it is an IDE controller. In its smart + * mode its actually quite a capable hardware raid controller disguised + * as an IDE controller. Smart mode only understands DMA read/write and + * identify, none of the fancier commands apply. The IT8211 is identical + * in other respects but lacks the raid mode. + * + * Errata: + * o Rev 0x10 also requires master/slave hold the same DMA timings and + * cannot do ATAPI MWDMA. + * o The identify data for raid volumes lacks CHS info (technically ok) + * but also fails to set the LBA28 and other bits. We fix these in + * the IDE probe quirk code. + * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode + * raid then the controller firmware dies + * o Smart mode without RAID doesn't clear all the necessary identify + * bits to reduce the command set to the one used + * + * This has a few impacts on the driver + * - In pass through mode we do all the work you would expect + * - In smart mode the clocking set up is done by the controller generally + * but we must watch the other limits and filter. + * - There are a few extra vendor commands that actually talk to the + * controller but only work PIO with no IRQ. + * + * Vendor areas of the identify block in smart mode are used for the + * timing and policy set up. Each HDD in raid mode also has a serial + * block on the disk. The hardware extra commands are get/set chip status, + * rebuild, get rebuild status. + * + * In Linux the driver supports pass through mode as if the device was + * just another IDE controller. If the smart mode is running then + * volumes are managed by the controller firmware and each IDE "disk" + * is a raid volume. Even more cute - the controller can do automated + * hotplug and rebuild. + * + * The pass through controller itself is a little demented. It has a + * flaw that it has a single set of PIO/MWDMA timings per channel so + * non UDMA devices restrict each others performance. It also has a + * single clock source per channel so mixed UDMA100/133 performance + * isn't perfect and we have to pick a clock. Thankfully none of this + * matters in smart mode. ATAPI DMA is not currently supported. + * + * It seems the smart mode is a win for RAID1/RAID10 but otherwise not. + * + * TODO + * - ATAPI UDMA is ok but not MWDMA it seems + * - RAID configuration ioctls + * - Move to libata once it grows up + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct it821x_dev +{ + unsigned int smart:1, /* Are we in smart raid mode */ + timing10:1; /* Rev 0x10 */ + u8 clock_mode; /* 0, ATA_50 or ATA_66 */ + u8 want[2][2]; /* Mode/Pri log for master slave */ + /* We need these for switching the clock when DMA goes on/off + The high byte is the 66Mhz timing */ + u16 pio[2]; /* Cached PIO values */ + u16 mwdma[2]; /* Cached MWDMA values */ + u16 udma[2]; /* Cached UDMA values (per drive) */ +}; + +#define ATA_66 0 +#define ATA_50 1 +#define ATA_ANY 2 + +#define UDMA_OFF 0 +#define MWDMA_OFF 0 + +/* + * We allow users to force the card into non raid mode without + * flashing the alternative BIOS. This is also neccessary right now + * for embedded platforms that cannot run a PC BIOS but are using this + * device. + */ + +static int it8212_noraid; + +/** + * it821x_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 it821x_program(ide_drive_t *drive, u16 timing) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_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); +} + +/** + * it821x_program_udma - program the UDMA registers + * @drive: drive to tune + * + * Program the UDMA timing for this drive according to the + * current clock. + */ + +static void it821x_program_udma(ide_drive_t *drive, u16 timing) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int channel = hwif->channel; + int unit = drive->select.b.unit; + u8 conf; + + /* Program UDMA timing bits */ + if(itdev->clock_mode == ATA_66) + conf = timing >> 8; + else + conf = timing & 0xFF; + if(itdev->timing10 == 0) + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf); + else { + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf); + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf); + } +} + + +/** + * it821x_clock_strategy + * @hwif: hardware interface + * + * Select between the 50 and 66Mhz base clocks to get the best + * results for this interface. + */ + +static void it821x_clock_strategy(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_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) { + it821x_program_udma(pair, itdev->udma[1-unit]); + it821x_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) { + it821x_program_udma(drive, itdev->udma[unit]); + it821x_program(drive, itdev->pio[unit]); + } +} + +/** + * it821x_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 u8 it821x_ratemask (ide_drive_t *drive) +{ + u8 mode = 4; + if (!eighty_ninty_three(drive)) + mode = min(mode, (u8)1); + return mode; +} + +/** + * it821x_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 it821x_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_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]; + it821x_clock_strategy(drive); + it821x_program(drive, itdev->pio[unit]); +} + +/** + * it821x_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 it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + int channel = hwif->channel; + u8 conf; + + static u16 dma[] = { 0x8866, 0x3222, 0x3121 }; + static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY }; + + itdev->want[unit][1] = mwdma_want[mode_wanted]; + itdev->want[unit][0] = 2; /* MWDMA is low priority */ + itdev->mwdma[unit] = dma[mode_wanted]; + itdev->udma[unit] = UDMA_OFF; + + /* UDMA bits off - Revision 0x10 do them in pairs */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(itdev->timing10) + conf |= channel ? 0x60: 0x18; + else + conf |= 1 << (3 + 2 * channel + unit); + pci_write_config_byte(hwif->pci_dev, 0x50, conf); + + it821x_clock_strategy(drive); + /* FIXME: do we need to program this ? */ + /* it821x_program(drive, itdev->mwdma[unit]); */ +} + +/** + * it821x_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 it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + int channel = hwif->channel; + u8 conf; + + static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 }; + static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 }; + + itdev->want[unit][1] = udma_want[mode_wanted]; + itdev->want[unit][0] = 3; /* UDMA is high priority */ + itdev->mwdma[unit] = MWDMA_OFF; + itdev->udma[unit] = udma[mode_wanted]; + if(mode_wanted >= 5) + itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */ + + /* UDMA on. Again revision 0x10 must do the pair */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(itdev->timing10) + conf &= channel ? 0x9F: 0xE7; + else + conf &= ~ (1 << (3 + 2 * channel + unit)); + pci_write_config_byte(hwif->pci_dev, 0x50, conf); + + it821x_clock_strategy(drive); + it821x_program_udma(drive, itdev->udma[unit]); + +} + +/** + * config_it821x_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_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + u8 unit = drive->select.b.unit; + ide_hwif_t *hwif = drive->hwif; + ide_drive_t *pair = &hwif->drives[1-unit]; + u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 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, 255, 5, NULL); + /* Trim PIO to the slowest of the master/slave */ + if(pair_pio < set_pio) + set_pio = pair_pio; + } + it821x_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); +} + +/** + * it821x_dma_read - DMA hook + * @drive: drive for DMA + * + * The IT821x has a single timing register for MWDMA and for PIO + * operations. As we flip back and forth we have to reload the + * clock. In addition the rev 0x10 device only works if the same + * timing value is loaded into the master and slave UDMA clock + * so we must also reload that. + * + * FIXME: we could figure out in advance if we need to do reloads + */ + +static void it821x_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + if(itdev->mwdma[unit] != MWDMA_OFF) + it821x_program(drive, itdev->mwdma[unit]); + else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10) + it821x_program_udma(drive, itdev->udma[unit]); + ide_dma_start(drive); +} + +/** + * it821x_dma_write - DMA hook + * @drive: drive for DMA stop + * + * The IT821x has a single timing register for MWDMA and for PIO + * operations. As we flip back and forth we have to reload the + * clock. + */ + +static int it821x_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + int unit = drive->select.b.unit; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int ret = __ide_dma_end(drive); + if(itdev->mwdma[unit] != MWDMA_OFF) + it821x_program(drive, itdev->pio[unit]); + return ret; +} + + +/** + * it821x_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 it821x_tune_chipset (ide_drive_t *drive, byte xferspeed) +{ + + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed); + + if(!itdev->smart) { + switch(speed) { + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + it821x_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: + it821x_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: + it821x_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, it821x_ratemask(drive)); + + config_it821x_chipset_for_pio(drive, !speed); + it821x_tune_chipset(drive, speed); + return ide_dma_enable(drive); +} + +/** + * it821x_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 it821x_config_drive_for_dma (ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + if (ide_use_dma(drive)) { + if (config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); + } + config_it821x_chipset_for_pio(drive, 1); + return hwif->ide_dma_off_quietly(drive); +} + +/** + * ata66_it821x - 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_it821x(ide_hwif_t *hwif) +{ + /* The reference driver also only does disk side */ + return 1; +} + +/** + * it821x_fixup - post init callback + * @hwif: interface + * + * This callback is run after the drives have been probed but + * before anything gets attached. It allows drivers to do any + * final tuning that is needed, or fixups to work around bugs. + */ + +static void __devinit it821x_fixups(ide_hwif_t *hwif) +{ + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int i; + + if(!itdev->smart) { + /* + * If we are in pass through mode then not much + * needs to be done, but we do bother to clear the + * IRQ mask as we may well be in PIO (eg rev 0x10) + * for now and we know unmasking is safe on this chipset. + */ + for (i = 0; i < 2; i++) { + ide_drive_t *drive = &hwif->drives[i]; + if(drive->present) + drive->unmask = 1; + } + return; + } + /* + * Perform fixups on smart mode. We need to "lose" some + * capabilities the firmware lacks but does not filter, and + * also patch up some capability bits that it forgets to set + * in RAID mode. + */ + + for(i = 0; i < 2; i++) { + ide_drive_t *drive = &hwif->drives[i]; + struct hd_driveid *id; + u16 *idbits; + + if(!drive->present) + continue; + id = drive->id; + idbits = (u16 *)drive->id; + + /* Check for RAID v native */ + if(strstr(id->model, "Integrated Technology Express")) { + /* In raid mode the ident block is slightly buggy + We need to set the bits so that the IDE layer knows + LBA28. LBA48 and DMA ar valid */ + id->capability |= 3; /* LBA28, DMA */ + id->command_set_2 |= 0x0400; /* LBA48 valid */ + id->cfs_enable_2 |= 0x0400; /* LBA48 on */ + /* Reporting logic */ + printk(KERN_INFO "%s: IT8212 %sRAID %d volume", + drive->name, + idbits[147] ? "Bootable ":"", + idbits[129]); + if(idbits[129] != 1) + printk("(%dK stripe)", idbits[146]); + printk(".\n"); + /* Now the core code will have wrongly decided no DMA + so we need to fix this */ + hwif->ide_dma_off_quietly(drive); +#ifdef CONFIG_IDEDMA_ONLYDISK + if (drive->media == ide_disk) +#endif + hwif->ide_dma_check(drive); + } else { + /* Non RAID volume. Fixups to stop the core code + doing unsupported things */ + id->field_valid &= 1; + id->queue_depth = 0; + id->command_set_1 = 0; + id->command_set_2 &= 0xC400; + id->cfsse &= 0xC000; + id->cfs_enable_1 = 0; + id->cfs_enable_2 &= 0xC400; + id->csf_default &= 0xC000; + id->word127 = 0; + id->dlf = 0; + id->csfo = 0; + id->cfa_power = 0; + printk(KERN_INFO "%s: Performing identify fixups.\n", + drive->name); + } + } + +} + +/** + * init_hwif_it821x - 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_it821x(ide_hwif_t *hwif) +{ + struct it821x_dev *idev = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL); + u8 conf; + + if(idev == NULL) { + printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n"); + goto fallback; + } + memset(idev, 0, sizeof(struct it821x_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; + } + + /* Pull the current clocks from 0x50 also */ + 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 "it821x: Revision 0x10, workarounds activated.\n"); + } + + hwif->speedproc = &it821x_tune_chipset; + hwif->tuneproc = &it821x_tuneproc; + + /* MWDMA/PIO clock switching for pass through mode */ + if(!idev->smart) { + hwif->ide_dma_start = &it821x_dma_start; + hwif->ide_dma_end = &it821x_dma_end; + } + + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + goto fallback; + + hwif->ultra_mask = 0x7f; + hwif->mwdma_mask = 0x07; + hwif->swdma_mask = 0x07; + + hwif->ide_dma_check = &it821x_config_drive_for_dma; + if (!(hwif->udma_four)) + hwif->udma_four = ata66_it821x(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; + return; +} + +static void __devinit it8212_disable_raid(struct pci_dev *dev) +{ + /* Reset local CPU, and set BIOS not ready */ + pci_write_config_byte(dev, 0x5E, 0x01); + + /* Set to bypass mode, and reset PCI bus */ + pci_write_config_byte(dev, 0x50, 0x00); + pci_write_config_word(dev, PCI_COMMAND, + PCI_COMMAND_PARITY | PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pci_write_config_word(dev, 0x40, 0xA0F3); + + pci_write_config_dword(dev,0x4C, 0x02040204); + pci_write_config_byte(dev, 0x42, 0x36); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0); +} + +static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name) +{ + u8 conf; + static char *mode[2] = { "pass through", "smart" }; + + /* Force the card into bypass mode if so requested */ + if (it8212_noraid) { + printk(KERN_INFO "it8212: forcing bypass mode.\n"); + it8212_disable_raid(dev); + } + pci_read_config_byte(dev, 0x50, &conf); + printk(KERN_INFO "it821x: controller in %s mode.\n", mode[conf & 1]); + return 0; +} + + +#define DECLARE_ITE_DEV(name_str) \ + { \ + .name = name_str, \ + .init_chipset = init_chipset_it821x, \ + .init_hwif = init_hwif_it821x, \ + .channels = 2, \ + .autodma = AUTODMA, \ + .bootable = ON_BOARD, \ + .fixup = it821x_fixups \ + } + +static ide_pci_device_t it821x_chipsets[] __devinitdata = { + /* 0 */ DECLARE_ITE_DEV("IT8212"), +}; + +/** + * it821x_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an ITE821x controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]); + return 0; +} + +static struct pci_device_id it821x_pci_tbl[] = { + { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, it821x_pci_tbl); + +static struct pci_driver driver = { + .name = "ITE821x IDE", + .id_table = it821x_pci_tbl, + .probe = it821x_init_one, +}; + +static int __init it821x_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(it821x_ide_init); + +module_param_named(noraid, it8212_noraid, int, S_IRUGO); +MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode"); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for the ITE 821x"); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/Makefile linux-2.6.10/drivers/ide/pci/Makefile --- linux.vanilla-2.6.10/drivers/ide/pci/Makefile 2004-12-25 21:14:31.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/Makefile 2004-12-29 23:05:37.000000000 +0000 @@ -9,10 +9,12 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o +obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o #obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o +obj-$(CONFIG_BLK_DEV_IT821X) += it821x.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.10/drivers/ide/pci/ns87415.c linux-2.6.10/drivers/ide/pci/ns87415.c --- linux.vanilla-2.6.10/drivers/ide/pci/ns87415.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/ns87415.c 2004-12-26 21:52:01.000000000 +0000 @@ -265,7 +265,7 @@ return; hwif->OUTB(0x60, hwif->dma_status); - hwif->dma_setup = &ns87415_ide_dma_setup; + hwif->ide_dma_setup = &ns87415_ide_dma_setup; hwif->ide_dma_check = &ns87415_ide_dma_check; hwif->ide_dma_end = &ns87415_ide_dma_end; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/pdc202xx_old.c linux-2.6.10/drivers/ide/pci/pdc202xx_old.c --- linux.vanilla-2.6.10/drivers/ide/pci/pdc202xx_old.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/pdc202xx_old.c 2004-12-26 22:08:33.000000000 +0000 @@ -592,7 +592,7 @@ if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) { if (!(hwif->udma_four)) hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1; - hwif->dma_start = &pdc202xx_old_ide_dma_start; + hwif->ide_dma_start = &pdc202xx_old_ide_dma_start; hwif->ide_dma_end = &pdc202xx_old_ide_dma_end; } hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/piix.c linux-2.6.10/drivers/ide/pci/piix.c --- linux.vanilla-2.6.10/drivers/ide/pci/piix.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/piix.c 2005-01-03 18:26:02.000000000 +0000 @@ -134,6 +134,7 @@ case PCI_DEVICE_ID_INTEL_82801EB_11: case PCI_DEVICE_ID_INTEL_ESB_2: case PCI_DEVICE_ID_INTEL_ICH6_19: + case PCI_DEVICE_ID_INTEL_ICH7_21: mode = 3; break; /* UDMA 66 capable */ @@ -445,6 +446,7 @@ case PCI_DEVICE_ID_INTEL_82801E_11: case PCI_DEVICE_ID_INTEL_ESB_2: case PCI_DEVICE_ID_INTEL_ICH6_19: + case PCI_DEVICE_ID_INTEL_ICH7_21: { unsigned int extra = 0; pci_read_config_dword(dev, 0x54, &extra); @@ -612,6 +614,7 @@ #endif { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_19, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21}, { 0, }, }; MODULE_DEVICE_TABLE(pci, piix_pci_tbl); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/piix.h linux-2.6.10/drivers/ide/pci/piix.h --- linux.vanilla-2.6.10/drivers/ide/pci/piix.h 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/piix.h 2005-01-03 18:26:02.000000000 +0000 @@ -57,7 +57,8 @@ /* 17 */ DECLARE_PIIX_DEV("ICH4"), /* 18 */ DECLARE_PIIX_DEV("ICH5-SATA"), /* 19 */ DECLARE_PIIX_DEV("ICH5"), - /* 20 */ DECLARE_PIIX_DEV("ICH6") + /* 20 */ DECLARE_PIIX_DEV("ICH6"), + /* 21 */ DECLARE_PIIX_DEV("ICH7"), }; #endif /* PIIX_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/serverworks.c linux-2.6.10/drivers/ide/pci/serverworks.c --- linux.vanilla-2.6.10/drivers/ide/pci/serverworks.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/serverworks.c 2004-12-26 18:50:17.000000000 +0000 @@ -359,11 +359,9 @@ else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { -// u32 pioreg = 0, dmareg = 0; /* Third Channel Test */ if (!(PCI_FUNC(dev->devfn) & 1)) { -#if 1 struct pci_dev * findev = NULL; u32 reg4c = 0; findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, @@ -375,19 +373,11 @@ reg4c |= 0x00000020; pci_write_config_dword(findev, 0x4C, reg4c); } -#endif outb_p(0x06, 0x0c00); dev->irq = inb_p(0x0c01); #if 0 - /* WE need to figure out how to get the correct one */ - printk("%s: interrupt %d\n", name, dev->irq); - if (dev->irq != 0x0B) - dev->irq = 0x0B; -#endif -#if 0 printk("%s: device class (0x%04x)\n", name, dev->class); -#else if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { dev->class &= ~0x000F0F00; // dev->class |= ~0x00000400; @@ -413,7 +403,8 @@ * interrupt pin to be set, and it is a compatibility * mode issue. */ - dev->irq = 0; + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) + dev->irq = 0; } // pci_read_config_dword(dev, 0x40, &pioreg) // pci_write_config_dword(dev, 0x40, 0x99999999); @@ -577,9 +568,6 @@ d->bootable = NEVER_BOARD; if (dev->resource[0].start == 0x01f1) d->bootable = ON_BOARD; - } else { - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) - return; } #if 0 if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) && @@ -625,10 +613,6 @@ .name = "Serverworks_IDE", .id_table = svwks_pci_tbl, .probe = svwks_init_one, -#if 0 /* FIXME: implement */ - .suspend = , - .resume = , -#endif }; static int svwks_ide_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/sgiioc4.c linux-2.6.10/drivers/ide/pci/sgiioc4.c --- linux.vanilla-2.6.10/drivers/ide/pci/sgiioc4.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/sgiioc4.c 2004-12-26 21:52:16.000000000 +0000 @@ -600,8 +600,8 @@ hwif->quirkproc = NULL; hwif->busproc = NULL; - hwif->dma_setup = &sgiioc4_ide_dma_setup; - hwif->dma_start = &sgiioc4_ide_dma_start; + hwif->ide_dma_setup = &sgiioc4_ide_dma_setup; + hwif->ide_dma_start = &sgiioc4_ide_dma_start; hwif->ide_dma_end = &sgiioc4_ide_dma_end; hwif->ide_dma_check = &sgiioc4_ide_dma_check; hwif->ide_dma_on = &sgiioc4_ide_dma_on; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/sl82c105.c linux-2.6.10/drivers/ide/pci/sl82c105.c --- linux.vanilla-2.6.10/drivers/ide/pci/sl82c105.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/sl82c105.c 2005-01-04 17:27:44.000000000 +0000 @@ -467,7 +467,7 @@ hwif->ide_dma_on = &sl82c105_ide_dma_on; hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly; hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq; - hwif->dma_start = &sl82c105_ide_dma_start; + hwif->ide_dma_start = &sl82c105_ide_dma_start; hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout; if (!noautodma) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/pci/trm290.c linux-2.6.10/drivers/ide/pci/trm290.c --- linux.vanilla-2.6.10/drivers/ide/pci/trm290.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/pci/trm290.c 2004-12-26 21:53:11.000000000 +0000 @@ -256,6 +256,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); @@ -292,9 +293,9 @@ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); #ifdef CONFIG_BLK_DEV_IDEDMA - hwif->dma_setup = &trm290_ide_dma_setup; - hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd; - hwif->dma_start = &trm290_ide_dma_start; + hwif->ide_dma_setup = &trm290_ide_dma_setup; + hwif->ide_dma_exec_cmd = &trm290_ide_dma_exec_cmd; + hwif->ide_dma_start = &trm290_ide_dma_start; hwif->ide_dma_end = &trm290_ide_dma_end; hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq; #endif /* CONFIG_BLK_DEV_IDEDMA */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/ppc/pmac.c linux-2.6.10/drivers/ide/ppc/pmac.c --- linux.vanilla-2.6.10/drivers/ide/ppc/pmac.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/ppc/pmac.c 2004-12-26 21:53:26.000000000 +0000 @@ -2016,9 +2016,9 @@ hwif->ide_dma_off_quietly = &__ide_dma_off_quietly; hwif->ide_dma_on = &__ide_dma_on; hwif->ide_dma_check = &pmac_ide_dma_check; - hwif->dma_setup = &pmac_ide_dma_setup; - hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd; - hwif->dma_start = &pmac_ide_dma_start; + hwif->ide_dma_setup = &pmac_ide_dma_setup; + hwif->ide_dma_exec_cmd = &pmac_ide_dma_exec_cmd; + hwif->ide_dma_start = &pmac_ide_dma_start; hwif->ide_dma_end = &pmac_ide_dma_end; hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq; hwif->ide_dma_host_off = &pmac_ide_dma_host_off; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/ide/setup-pci.c linux-2.6.10/drivers/ide/setup-pci.c --- linux.vanilla-2.6.10/drivers/ide/setup-pci.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/ide/setup-pci.c 2005-01-04 00:01:44.000000000 +0000 @@ -1,7 +1,8 @@ /* - * linux/drivers/ide/setup-pci.c Version 1.10 2002/08/19 + * linux/drivers/ide/setup-pci.c Version 1.14 2004/08/10 * * Copyright (c) 1998-2000 Andre Hedrick + * Copyright (c) 2004 Red Hat * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -11,6 +12,7 @@ * Use pci_set_master * Fix misreporting of I/O v MMIO problems * Initial fixups for simplex devices + * Hot unplug paths */ /* @@ -28,6 +30,7 @@ #include #include #include +#include #include #include @@ -42,7 +45,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 +90,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) { @@ -420,8 +425,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)); @@ -433,6 +448,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; @@ -722,19 +740,78 @@ ata_index_t index_list2 = do_ide_setup_pci_device(dev2, d, 0); if ((index_list.b.low & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list.b.low]); + probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.low], d->fixup); if ((index_list.b.high & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list.b.high]); + probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.high], d->fixup); if ((index_list2.b.low & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list2.b.low]); + probe_hwif_init_with_fixup(&ide_hwifs[index_list2.b.low], d->fixup); if ((index_list2.b.high & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index_list2.b.high]); + probe_hwif_init_with_fixup(&ide_hwifs[index_list2.b.high], d->fixup); create_proc_ide_interfaces(); } EXPORT_SYMBOL_GPL(ide_setup_pci_devices); + +static int ide_pci_try_unregister(struct pci_dev *dev) +{ + int i; + int err = 0; + ide_hwif_t *hwif = ide_hwifs; + + for(i = 0; i < MAX_HWIFS; i++) { + if(hwif->configured && hwif->pci_dev == dev) + err |= __ide_unregister_hwif(hwif); + i++; + hwif++; + } + return err; +} + +/** + * 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; + int err; + + down(&ide_cfg_sem); + + err = ide_pci_try_unregister(dev); + + if(err < 0) { + printk(KERN_ERR "ide: PCI interfaces busy during hotplug. Waiting....\n"); + for(i = 0; i < MAX_HWIFS; i++) { + if(hwif->configured && hwif->pci_dev == dev) + removed_hwif_iops(hwif); + i++; + hwif++; + } + } + /* Should drop this out to a work queue I think ? */ + while(ide_pci_try_unregister(dev) < 0) + msleep(1000); + 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.10/drivers/input/gameport/Kconfig linux-2.6.10/drivers/input/gameport/Kconfig --- linux.vanilla-2.6.10/drivers/input/gameport/Kconfig 2004-12-25 21:14:37.000000000 +0000 +++ linux-2.6.10/drivers/input/gameport/Kconfig 2004-12-26 17:20:56.000000000 +0000 @@ -84,7 +84,7 @@ tristate "ForteMedia FM801 gameport support" depends on GAMEPORT -config GAMEPORT_CS461x +config GAMEPORT_CS461X tristate "Crystal SoundFusion gameport support" depends on GAMEPORT diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/input/joystick/sidewinder.c linux-2.6.10/drivers/input/joystick/sidewinder.c --- linux.vanilla-2.6.10/drivers/input/joystick/sidewinder.c 2004-12-25 21:14:37.000000000 +0000 +++ linux-2.6.10/drivers/input/joystick/sidewinder.c 2005-01-06 22:03:00.000000000 +0000 @@ -45,7 +45,7 @@ * as well as break everything. */ -#define SW_DEBUG +/* #define SW_DEBUG */ #define SW_START 400 /* The time we wait for the first bit [400 us] */ #define SW_STROBE 45 /* Max time per bit [45 us] */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/input/keyboard/atkbd.c linux-2.6.10/drivers/input/keyboard/atkbd.c --- linux.vanilla-2.6.10/drivers/input/keyboard/atkbd.c 2004-12-25 21:14:37.000000000 +0000 +++ linux-2.6.10/drivers/input/keyboard/atkbd.c 2004-12-26 18:50:36.000000000 +0000 @@ -365,9 +365,13 @@ break; case ATKBD_KEY_UNKNOWN: if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { +#if 0 +/* Quite a few key switchers and other tools trigger this and it confuses + people who can do nothing about it */ printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " "like XFree86, might be trying access hardware directly.\n", data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); +#endif } else { printk(KERN_WARNING "atkbd.c: Unknown key %s " "(%s set %d, code %#x on %s).\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/input/serio/i8042.c linux-2.6.10/drivers/input/serio/i8042.c --- linux.vanilla-2.6.10/drivers/input/serio/i8042.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/input/serio/i8042.c 2004-12-26 22:48:07.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -666,6 +667,71 @@ } +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_get_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); + + pci_dev_put(usb); + + 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 +740,7 @@ static int i8042_controller_init(void) { + int tries = 0; unsigned long flags; /* @@ -703,9 +770,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; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/input/serio/maceps2.c linux-2.6.10/drivers/input/serio/maceps2.c --- linux.vanilla-2.6.10/drivers/input/serio/maceps2.c 2004-12-25 21:14:37.000000000 +0000 +++ linux-2.6.10/drivers/input/serio/maceps2.c 2005-01-06 22:27:31.000000000 +0000 @@ -90,7 +90,7 @@ { struct maceps2_data *data = (struct maceps2_data *)dev->port_data; - if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { + if (request_irq(data->irq, maceps2_interrupt, 0, "PS2 port", dev)) { printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); return -EBUSY; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/isdn/hardware/avm/b1pcmcia.c linux-2.6.10/drivers/isdn/hardware/avm/b1pcmcia.c --- linux.vanilla-2.6.10/drivers/isdn/hardware/avm/b1pcmcia.c 2004-12-25 21:14:27.000000000 +0000 +++ linux-2.6.10/drivers/isdn/hardware/avm/b1pcmcia.c 2004-12-26 22:16:30.000000000 +0000 @@ -200,7 +200,6 @@ { char *p; char rev[32]; - int err; if ((p = strchr(revision, ':')) != 0 && p[1]) { strlcpy(rev, p + 2, 32); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/macintosh/mediabay.c linux-2.6.10/drivers/macintosh/mediabay.c --- linux.vanilla-2.6.10/drivers/macintosh/mediabay.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/macintosh/mediabay.c 2004-12-26 18:51:47.000000000 +0000 @@ -82,6 +82,7 @@ #ifdef CONFIG_BLK_DEV_IDE void __iomem *cd_base; int cd_index; + ide_hwif_t *cd_hwif; int cd_irq; int cd_retry; #endif @@ -569,7 +570,7 @@ ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL); hw.irq = bay->cd_irq; hw.chipset = ide_pmac; - bay->cd_index = ide_register_hw(&hw, NULL); + bay->cd_index = ide_register_hw(&hw, &bay->cd_hwif); pmu_resume(); } if (bay->cd_index == -1) { @@ -600,7 +601,7 @@ if (bay->cd_index >= 0) { printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); - ide_unregister(bay->cd_index); + ide_unregister_hwif(bay->cd_hwif); bay->cd_index = -1; } if (bay->cd_retry) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/macintosh/via-pmu.c linux-2.6.10/drivers/macintosh/via-pmu.c --- linux.vanilla-2.6.10/drivers/macintosh/via-pmu.c 2004-12-25 21:15:34.000000000 +0000 +++ linux-2.6.10/drivers/macintosh/via-pmu.c 2005-01-06 22:27:31.000000000 +0000 @@ -418,7 +418,7 @@ } if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) { - if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0)) + if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1-ADB", (void *)0)) printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq); gpio_irq_enabled = 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/media/dvb/frontends/Kconfig linux-2.6.10/drivers/media/dvb/frontends/Kconfig --- linux.vanilla-2.6.10/drivers/media/dvb/frontends/Kconfig 2004-12-25 21:15:39.000000000 +0000 +++ linux-2.6.10/drivers/media/dvb/frontends/Kconfig 2004-12-29 22:59:55.000000000 +0000 @@ -46,6 +46,7 @@ config DVB_SP8870 tristate "Spase sp8870 based" depends on DVB_CORE + select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -56,6 +57,7 @@ config DVB_SP887X tristate "Spase sp887x based" depends on DVB_CORE + select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -84,6 +86,7 @@ config DVB_TDA1004X tristate "Philips TDA10045H/TDA10046H based" depends on DVB_CORE + select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/media/video/Kconfig linux-2.6.10/drivers/media/video/Kconfig --- linux.vanilla-2.6.10/drivers/media/video/Kconfig 2004-12-25 21:15:39.000000000 +0000 +++ linux-2.6.10/drivers/media/video/Kconfig 2005-01-03 19:13:07.000000000 +0000 @@ -305,6 +305,7 @@ tristate "Conexant 2388x (bt878 successor) support" depends on VIDEO_DEV && PCI && EXPERIMENTAL select I2C_ALGOBIT + select FW_LOADER select VIDEO_BTCX select VIDEO_BUF select VIDEO_TUNER diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/mmc/mmc.c linux-2.6.10/drivers/mmc/mmc.c --- linux.vanilla-2.6.10/drivers/mmc/mmc.c 2004-12-25 21:14:14.000000000 +0000 +++ linux-2.6.10/drivers/mmc/mmc.c 2005-01-03 18:20:37.000000000 +0000 @@ -301,14 +301,15 @@ #define UNSTUFF_BITS(resp,start,size) \ ({ \ - const u32 __mask = (1 << (size)) - 1; \ + const int __size = size; \ + const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ const int __off = 3 - ((start) / 32); \ const int __shft = (start) & 31; \ u32 __res; \ \ __res = resp[__off] >> __shft; \ - if ((size) + __shft >= 32) \ - __res |= resp[__off-1] << (32 - __shft); \ + if (__size + __shft > 32) \ + __res |= resp[__off-1] << ((32 - __shft) % 32); \ __res & __mask; \ }) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/3c59x.c linux-2.6.10/drivers/net/3c59x.c --- linux.vanilla-2.6.10/drivers/net/3c59x.c 2004-12-25 21:15:39.000000000 +0000 +++ linux-2.6.10/drivers/net/3c59x.c 2004-12-26 17:19:18.000000000 +0000 @@ -416,7 +416,7 @@ HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800, EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000, - EXTRA_PREAMBLE=0x8000, }; + EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, }; enum vortex_chips { CH_3C590 = 0, @@ -491,9 +491,9 @@ {"3c595 Vortex 100base-MII", PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, {"3c900 Boomerang 10baseT", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, {"3c900 Boomerang 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps Combo", @@ -504,9 +504,9 @@ {"3c900B-FL Cyclone 10base-FL", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c905 Boomerang 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, {"3c905 Boomerang 100baseT4", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, {"3c905B Cyclone 100baseTx", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, @@ -3168,7 +3168,8 @@ pci_restore_state(VORTEX_PCI(vp)); } /* Should really use issue_and_wait() here */ - outw(TotalReset|0x14, dev->base_addr + EL3_CMD); + outw(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14), + dev->base_addr + EL3_CMD); pci_free_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/pcnet32.c linux-2.6.10/drivers/net/pcnet32.c --- linux.vanilla-2.6.10/drivers/net/pcnet32.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/net/pcnet32.c 2004-12-26 17:18:20.000000000 +0000 @@ -1429,26 +1429,32 @@ val |= 0x10; lp->a.write_csr (ioaddr, 124, val); - /* 24 Jun 2004 according AMD, in order to change the PHY, - * DANAS (or DISPM for 79C976) must be set; then select the speed, - * duplex, and/or enable auto negotiation, and clear DANAS */ - if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { - lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* disable Auto Negotiation, set 10Mpbs, HD */ - val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; - if (lp->options & PCNET32_PORT_FD) - val |= 0x10; - if (lp->options & PCNET32_PORT_100) - val |= 0x08; - lp->a.write_bcr (ioaddr, 32, val); + /* Skip PHY selection on AT2701FX, looses link otherwise */ + if(lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT && + lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX ) { + printk(KERN_DEBUG "pcnet32: Skipping PHY selection.\n"); } else { - if (lp->options & PCNET32_PORT_ASEL) { - lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* enable auto negotiate, setup, disable fd */ - val = lp->a.read_bcr(ioaddr, 32) & ~0x98; - val |= 0x20; - lp->a.write_bcr(ioaddr, 32, val); - } + /* 24 Jun 2004 according AMD, in order to change the PHY, + * DANAS (or DISPM for 79C976) must be set; then select the speed, + * duplex, and/or enable auto negotiation, and clear DANAS */ + if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); + /* disable Auto Negotiation, set 10Mpbs, HD */ + val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; + if (lp->options & PCNET32_PORT_FD) + val |= 0x10; + if (lp->options & PCNET32_PORT_100) + val |= 0x08; + lp->a.write_bcr (ioaddr, 32, val); + } else { + if (lp->options & PCNET32_PORT_ASEL) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); + /* enable auto negotiate, setup, disable fd */ + val = lp->a.read_bcr(ioaddr, 32) & ~0x98; + val |= 0x20; + lp->a.write_bcr(ioaddr, 32, val); + } + } } #ifdef DO_DXSUFLO diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/tulip/media.c linux-2.6.10/drivers/net/tulip/media.c --- linux.vanilla-2.6.10/drivers/net/tulip/media.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/net/tulip/media.c 2004-12-30 22:28:58.000000000 +0000 @@ -81,6 +81,25 @@ return retval & 0xffff; } + if(tp->chip_id == ULI526X && tp->revision >= 0x40) { + int value; + int i = 1000; + + value = ioread32(ioaddr + CSR9); + iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9); + + value = (phy_id << 21) | (location << 16) | 0x80000000; + iowrite32(value, ioaddr + CSR10); + + while(--i > 0) { + mdio_delay(); + if(ioread32(ioaddr + CSR10) & 0x10000000) + break; + } + retval = ioread32(ioaddr + CSR10); + spin_unlock_irqrestore(&tp->mii_lock, flags); + return retval & 0xFFFF; + } /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); @@ -140,7 +159,23 @@ spin_unlock_irqrestore(&tp->mii_lock, flags); return; } - + if (tp->chip_id == ULI526X && tp->revision >= 0x40) { + int value; + int i = 1000; + + value = ioread32(ioaddr + CSR9); + iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9); + + value = (phy_id << 21) | (location << 16) | 0x40000000 | (val & 0xFFFF); + iowrite32(value, ioaddr + CSR10); + + while(--i > 0) { + if (ioread32(ioaddr + CSR10) & 0x10000000) + break; + } + spin_unlock_irqrestore(&tp->mii_lock, flags); + } + /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/tulip/timer.c linux-2.6.10/drivers/net/tulip/timer.c --- linux.vanilla-2.6.10/drivers/net/tulip/timer.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/net/tulip/timer.c 2004-12-29 23:50:40.000000000 +0000 @@ -39,6 +39,7 @@ case MX98713: case COMPEX9881: case DM910X: + case ULI526X: default: { struct medialeaf *mleaf; unsigned char *p; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/tulip/tulip_core.c linux-2.6.10/drivers/net/tulip/tulip_core.c --- linux.vanilla-2.6.10/drivers/net/tulip/tulip_core.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/net/tulip/tulip_core.c 2004-12-29 23:50:19.000000000 +0000 @@ -197,6 +197,10 @@ /* RS7112 */ { "Conexant LANfinity", 256, 0x0001ebef, HAS_MII | HAS_ACPI, tulip_timer }, + + /* ULi526X */ + { "ULi M5261/M5263", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI, tulip_timer }, }; @@ -233,7 +237,8 @@ { 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1737, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, /* ALi 1563 integrated ethernet */ + { 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */ + { 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */ { 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */ { } /* terminate list */ }; @@ -514,7 +519,7 @@ dev->name); } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 - || tp->chip_id == DM910X) { + || tp->chip_id == DM910X || tp->chip_id == ULI526X) { printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12), @@ -1215,6 +1220,22 @@ } #endif +/* + * Chips that have the MRM/reserved bit quirk and the burst quirk. That + * is the DM910X and the on chip ULi devices + */ + +static int tulip_uli_dm_quirk(struct pci_dev *pdev) +{ + if (pdev->vendor == 0x1282 && pdev->device == 0x9102) + return 1; + if (pdev->vendor == 0x10b9 && pdev->device == 0x5261) + return 1; + if (pdev->vendor == 0x10b9 && pdev->device == 0x5263) + return 1; + return 0; +} + static int __devinit tulip_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1303,17 +1324,12 @@ csr0 &= ~0xfff10000; /* zero reserved bits 31:20, 16 */ /* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */ - if ((pdev->vendor == 0x1282 && pdev->device == 0x9102) - || (pdev->vendor == 0x10b9 && pdev->device == 0x5261)) + if (tulip_uli_dm_quirk(pdev)) { csr0 &= ~0x01f100ff; - #if defined(__sparc__) - /* DM9102A needs 32-dword alignment/burst length on sparc - chip bug? */ - if ((pdev->vendor == 0x1282 && pdev->device == 0x9102) - || (pdev->vendor == 0x10b9 && pdev->device == 0x5261)) csr0 = (csr0 & ~0xff00) | 0xe000; #endif - + } /* * And back to business */ @@ -1658,6 +1674,7 @@ switch (chip_idx) { case DC21140: case DM910X: + case ULI526X: default: if (tp->mtable) iowrite32(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/tulip/tulip.h linux-2.6.10/drivers/net/tulip/tulip.h --- linux.vanilla-2.6.10/drivers/net/tulip/tulip.h 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/net/tulip/tulip.h 2004-12-29 23:49:34.000000000 +0000 @@ -88,6 +88,7 @@ I21145, DM910X, CONEXANT, + ULI526X }; @@ -481,8 +482,11 @@ static inline void tulip_restart_rxtx(struct tulip_private *tp) { - tulip_stop_rxtx(tp); - udelay(5); + if(!(tp->chip_id == ULI526X && + (tp->revision == 0x40 || tp->revision == 0x50))) { + tulip_stop_rxtx(tp); + udelay(5); + } tulip_start_rxtx(tp); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/wan/cosa.c linux-2.6.10/drivers/net/wan/cosa.c --- linux.vanilla-2.6.10/drivers/net/wan/cosa.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/net/wan/cosa.c 2005-01-06 22:07:23.000000000 +0000 @@ -642,11 +642,11 @@ return; } chan->pppdev.dev = d; - sppp_attach(&chan->pppdev); d->base_addr = chan->cosa->datareg; d->irq = chan->cosa->irq; d->dma = chan->cosa->dma; d->priv = chan; + sppp_attach(&chan->pppdev); if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(d); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/wan/hostess_sv11.c linux-2.6.10/drivers/net/wan/hostess_sv11.c --- linux.vanilla-2.6.10/drivers/net/wan/hostess_sv11.c 2004-12-25 21:14:21.000000000 +0000 +++ linux-2.6.10/drivers/net/wan/hostess_sv11.c 2005-01-06 22:28:17.000000000 +0000 @@ -263,7 +263,7 @@ /* We want a fast IRQ for this device. Actually we'd like an even faster IRQ ;) - This is one driver RtLinux is made for */ - if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV/11", dev)<0) + if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV11", dev)<0) { printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq); goto fail1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/net/wan/sdla.c linux-2.6.10/drivers/net/wan/sdla.c --- linux.vanilla-2.6.10/drivers/net/wan/sdla.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/net/wan/sdla.c 2005-01-07 15:49:56.000000000 +0000 @@ -1306,6 +1306,8 @@ case SDLA_WRITEMEM: case SDLA_READMEM: + if(!capable(CAP_SYS_RAWIO)) + return -EPERM; return(sdla_xfer(dev, ifr->ifr_data, cmd == SDLA_READMEM)); case SDLA_START: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/parport/parport_pc.c linux-2.6.10/drivers/parport/parport_pc.c --- linux.vanilla-2.6.10/drivers/parport/parport_pc.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/parport/parport_pc.c 2005-01-03 18:22:03.000000000 +0000 @@ -3176,7 +3176,6 @@ #ifdef MODULE static const char *irq[PARPORT_PC_MAX_PORTS]; static const char *dma[PARPORT_PC_MAX_PORTS]; -static char *init_mode; MODULE_PARM_DESC(io, "Base I/O address (SPP regs)"); module_param_array(io, int, NULL, 0); @@ -3192,8 +3191,9 @@ module_param(verbose_probing, int, 0644); #endif #ifdef CONFIG_PCI +static char *init_mode; MODULE_PARM_DESC(init_mode, "Initialise mode for VIA VT8231 port (spp, ps2, epp, ecp or ecpepp)"); -MODULE_PARM(init_mode, "s"); +module_param(init_mode, charp, 0); #endif static int __init parse_parport_params(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/parport/probe.c linux-2.6.10/drivers/parport/probe.c --- linux.vanilla-2.6.10/drivers/parport/probe.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/parport/probe.c 2005-01-06 22:21:38.000000000 +0000 @@ -164,8 +164,16 @@ if (retval != 2) goto end_id; idlen = (length[0] << 8) + length[1] - 2; - if (idlen < len) + /* + * Check if the caller-allocated buffer is large enough + * otherwise bail out or there will be an at least off by one. + */ + if (idlen + 1 < len) len = idlen; + else { + retval = -EINVAL; + goto out; + } retval = parport_read (dev->port, buffer, len); if (retval != len) @@ -205,11 +213,12 @@ buffer[len] = '\0'; parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); } - parport_release (dev); if (retval > 2) parse_data (dev->port, dev->daisy, buffer); +out: + parport_release (dev); parport_close (dev); return retval; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/pci/quirks.c linux-2.6.10/drivers/pci/quirks.c --- linux.vanilla-2.6.10/drivers/pci/quirks.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/pci/quirks.c 2005-01-03 19:07:01.000000000 +0000 @@ -479,26 +479,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); -static void quirk_via_irqpic(struct pci_dev *dev) -{ - u8 irq, new_irq = dev->irq & 0xf; - - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); - - if (new_irq != irq) { - printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n", - pci_name(dev), irq, new_irq); - - udelay(15); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); - } -} -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic ); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic ); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic ); -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, quirk_via_irqpic ); - - /* * PIIX3 USB: We have to disable USB interrupts that are * hardwired to PIRQD# and may be shared with an @@ -691,12 +671,14 @@ /* * VIA northbridges care about PCI_INTERRUPT_LINE */ -int interrupt_line_quirk; +int via_interrupt_line_quirk; static void __devinit quirk_via_bridge(struct pci_dev *pdev) { - if(pdev->devfn == 0) - interrupt_line_quirk = 1; + if(pdev->devfn == 0) { + printk(KERN_INFO "PCI: Via IRQ fixup\n"); + via_interrupt_line_quirk = 1; + } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge ); @@ -1162,6 +1144,10 @@ case 0x2653: ich = 6; break; + case 0x27c0: + case 0x27c4: + ich = 7; + break; default: /* we do not handle this PCI device */ return; @@ -1181,7 +1167,7 @@ else return; /* not in combined mode */ } else { - WARN_ON(ich != 6); + WARN_ON((ich != 6) && (ich != 7)); tmp &= 0x3; /* interesting bits 1:0 */ if (tmp & (1 << 0)) comb = (1 << 2); /* PATA port 0, SATA port 1 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/aacraid/aacraid.h linux-2.6.10/drivers/scsi/aacraid/aacraid.h --- linux.vanilla-2.6.10/drivers/scsi/aacraid/aacraid.h 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/aacraid/aacraid.h 2004-12-29 22:48:46.000000000 +0000 @@ -444,7 +444,24 @@ * dma mask such that fib memory will be allocated where the * adapter firmware can get to it. */ -#define AAC_QUIRK_31BIT 1 +#define AAC_QUIRK_31BIT 0x0001 + +/* + * Some adapter firmware, when the raid card's cache is turned off, can not + * split up scatter gathers in order to deal with the limits of the + * underlying CHIM. This limit is 34 scatter gather elements. + */ +#define AAC_QUIRK_34SG 0x0002 + +/* + * This adapter is a slave (no Firmware) + */ +#define AAC_QUIRK_SLAVE 0x0004 + +/* + * This adapter is a master. + */ +#define AAC_QUIRK_MASTER 0x0008 /* * The adapter interface specs all queues to be located in the same diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/aacraid/commsup.c linux-2.6.10/drivers/scsi/aacraid/commsup.c --- linux.vanilla-2.6.10/drivers/scsi/aacraid/commsup.c 2004-12-25 21:14:35.000000000 +0000 +++ linux-2.6.10/drivers/scsi/aacraid/commsup.c 2004-12-26 18:53:37.000000000 +0000 @@ -781,6 +781,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) { struct hw_fib * hw_fib = fibptr->hw_fib; +#if 0 /* * Set the status of this FIB to be Invalid parameter. * @@ -788,6 +789,8 @@ */ *(u32 *)hw_fib->data = cpu_to_le32(ST_OK); fib_adapter_complete(fibptr, sizeof(u32)); + /* This will be done on our return */ +#endif } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/aacraid/linit.c linux-2.6.10/drivers/scsi/aacraid/linit.c --- linux.vanilla-2.6.10/drivers/scsi/aacraid/linit.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/aacraid/linit.c 2004-12-29 22:48:46.000000000 +0000 @@ -98,31 +98,35 @@ { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 20 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ { 0x9005, 0x0286, 0x9005, 0x028d, 0, 0, 21 }, /* ASR-2130S (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 22 }, /* Jupiter Platform */ - { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 23 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ - { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 24 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ - { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 25 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ - { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 26 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ - { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 27 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ - { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 28 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ - { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 29 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* AAR-2610SA PCI SATA 6ch */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 31 }, /* ASR-2240S */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 32 }, /* ASR-4005SAS */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 33 }, /* ASR-4000SAS */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 34 }, /* ASR-4800SAS */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 35 }, /* ASR-4805SAS */ - - { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 36 }, /* Perc 320/DC*/ - { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 37 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 38 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 39 }, /* Dell PERC2/QC */ - { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 40 }, /* HP NetRAID-4M */ - - { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 41 }, /* Dell Catchall */ - { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 42 }, /* Legend Catchall */ - { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 43 }, /* Adaptec Catch All */ - { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 44 }, /* Adaptec Rocket Catch All */ + { 0x9005, 0x0286, 0x9005, 0x029b, 0, 0, 22 }, /* AAR-2820SA (Intruder) */ + { 0x9005, 0x0286, 0x9005, 0x029c, 0, 0, 23 }, /* AAR-2620SA (Intruder) */ + { 0x9005, 0x0286, 0x9005, 0x029d, 0, 0, 24 }, /* AAR-2420SA (Intruder) */ + { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 25 }, /* Callisto Jupiter Platform */ + { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 26 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ + { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 27 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ + { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 28 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ + { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 29 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ + { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 30 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ + { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 31 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ + { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 32 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ + { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 33 }, /* AAR-2610SA PCI SATA 6ch */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 34 }, /* ASR-2240S (SabreExpress) */ + { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 35 }, /* ASR-4005SAS */ + { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 36 }, /* IBM 8i (AvonPark) */ + { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 37 }, /* ASR-4000SAS (BlackBird) */ + { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 38 }, /* ASR-4800SAS (Marauder-X) */ + { 0x9005, 0x0285, 0x9005, 0x029A, 0, 0, 39 }, /* ASR-4805SAS (Marauder-E) */ + + { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 40 }, /* Perc 320/DC*/ + { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 41 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 42 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 43 }, /* Dell PERC2/QC */ + { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 44 }, /* HP NetRAID-4M */ + + { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 45 }, /* Dell Catchall */ + { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 46 }, /* Legend Catchall */ + { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 47 }, /* Adaptec Catch All */ + { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 48 }, /* Adaptec Rocket Catch All */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -133,22 +137,22 @@ * for the card. At that time we can remove the channels from here */ static struct aac_driver_ident aac_drivers[] = { - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 2/Si (Iguana/PERC2Si) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Opal/PERC3Di) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Si (SlimFast/PERC3Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Viper/PERC3DiV) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Lexus/PERC3DiL) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Dagger/PERC3DiD) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT }, /* PERC 3/Di (Boxster/PERC3DiB) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT }, /* catapult */ - { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT }, /* tomcat */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT }, /* Adaptec 2120S (Crusader) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT }, /* Adaptec 2200S (Vulcan-2m) */ - { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT }, /* Legend S220 (Legend Crusader) */ - { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT }, /* Legend S230 (Legend Vulcan) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */ + { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier) */ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado) */ @@ -156,30 +160,34 @@ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2130S PCI-X ", 1 }, /* ASR-2130S (Lancer) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2 }, /* Jupiter Platform */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2820SA ", 1 }, /* AAR-2820SA (Intruder) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2620SA ", 1 }, /* AAR-2620SA (Intruder) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2420SA ", 1 }, /* AAR-2420SA (Intruder) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ { aac_rx_init, "aacraid", "DELL ", "CERC SR2 ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "SO-DIMM SATA ZCR", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2026ZCR ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2610SA ", 1 }, /* SATA 6Ch (Bearcat) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS */ - - { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4 }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4 }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT }, /* Dell PERC2/QC */ - { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4 }, /* HP NetRAID-4M */ - - { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Dell Catchall */ - { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Legend Catchall */ - { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT }, /* Adaptec Catch All */ + { aac_rx_init, "aacraid", "IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */ + + { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ + { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ + { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ + { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell PERC2/QC */ + { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */ + + { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */ + { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */ + { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */ { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec Rocket Catch All */ }; @@ -350,7 +358,7 @@ } /** - * aac_queuedepth - compute queue depths + * aac_slave_configure - compute queue depths * @sdev: SCSI device we are considering * * Selects queue depths for each target device based on the host adapter's diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/ahci.c linux-2.6.10/drivers/scsi/ahci.c --- linux.vanilla-2.6.10/drivers/scsi/ahci.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/ahci.c 2005-01-03 19:07:01.000000000 +0000 @@ -239,9 +239,13 @@ static struct pci_device_id ahci_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, + board_ahci }, /* ICH6 */ { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, + board_ahci }, /* ICH6M */ + { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ICH7 */ + { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ICH7M */ { } /* terminate list */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/ata_piix.c linux-2.6.10/drivers/scsi/ata_piix.c --- linux.vanilla-2.6.10/drivers/scsi/ata_piix.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/ata_piix.c 2005-01-03 19:07:01.000000000 +0000 @@ -60,6 +60,7 @@ piix4_pata = 2, ich6_sata = 3, ich6_sata_rm = 4, + ich7_sata = 5, }; static int piix_init_one (struct pci_dev *pdev, @@ -90,6 +91,8 @@ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, { } /* terminate list */ }; @@ -236,6 +239,18 @@ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, + + /* ich7_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, }; static struct pci_bits piix_enable_bits[] = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/ide-scsi.c linux-2.6.10/drivers/scsi/ide-scsi.c --- linux.vanilla-2.6.10/drivers/scsi/ide-scsi.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/ide-scsi.c 2004-12-26 22:23:48.000000000 +0000 @@ -569,7 +569,7 @@ atapi_output_bytes(drive, scsi->pc->c, 12); if (test_bit (PC_DMA_OK, &pc->flags)) { set_bit (PC_DMA_IN_PROGRESS, &pc->flags); - hwif->dma_start(drive); + hwif->ide_dma_start(drive); } return ide_started; } @@ -636,7 +636,7 @@ feature.all = 0; if (drive->using_dma && !idescsi_map_sg(drive, pc)) { hwif->sg_mapped = 1; - feature.b.dma = !hwif->dma_setup(drive); + feature.b.dma = !hwif->ide_dma_setup(drive); hwif->sg_mapped = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/libata-core.c linux-2.6.10/drivers/scsi/libata-core.c --- linux.vanilla-2.6.10/drivers/scsi/libata-core.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/libata-core.c 2004-12-29 22:51:25.000000000 +0000 @@ -1919,7 +1919,24 @@ if (idx) ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } +/** + * ata_check_atapi_dma - Check whether ATAPI DMA can be supported + * @qc: Metadata associated with taskfile to check + * + * LOCKING: + * RETURNS: 0 when ATAPI DMA can be used + * nonzero otherwise + */ +int ata_check_atapi_dma(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + int rc = 0; /* Assume ATAPI DMA is OK by default */ + + if (ap->ops->check_atapi_dma) + rc = ap->ops->check_atapi_dma(qc); + return rc; +} /** * ata_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared @@ -2369,6 +2386,9 @@ unsigned long timeout = 0; switch (ap->pio_task_state) { + case PIO_ST_IDLE: + return; + case PIO_ST: ata_pio_block(ap); break; @@ -2385,18 +2405,14 @@ case PIO_ST_TMOUT: case PIO_ST_ERR: ata_pio_error(ap); - break; + return; } - if ((ap->pio_task_state != PIO_ST_IDLE) && - (ap->pio_task_state != PIO_ST_TMOUT) && - (ap->pio_task_state != PIO_ST_ERR)) { - if (timeout) - queue_delayed_work(ata_wq, &ap->pio_task, - timeout); - else - queue_work(ata_wq, &ap->pio_task); - } + if (timeout) + queue_delayed_work(ata_wq, &ap->pio_task, + timeout); + else + queue_work(ata_wq, &ap->pio_task); } static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, @@ -2405,7 +2421,6 @@ DECLARE_COMPLETION(wait); struct ata_queued_cmd *qc; unsigned long flags; - int using_pio = dev->flags & ATA_DFLAG_PIO; int rc; DPRINTK("ATAPI request sense\n"); @@ -2426,16 +2441,10 @@ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; qc->tf.command = ATA_CMD_PACKET; - if (using_pio) { - qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; - - qc->nbytes = SCSI_SENSE_BUFFERSIZE; - } else { - qc->tf.protocol = ATA_PROT_ATAPI_DMA; - qc->tf.feature |= ATAPI_PKT_DMA; - } + qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.lbam = (8 * 1024) & 0xff; + qc->tf.lbah = (8 * 1024) >> 8; + qc->nbytes = SCSI_SENSE_BUFFERSIZE; qc->waiting = &wait; qc->complete_fn = ata_qc_complete_noop; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/libata.h linux-2.6.10/drivers/scsi/libata.h --- linux.vanilla-2.6.10/drivers/scsi/libata.h 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/libata.h 2004-12-29 22:51:25.000000000 +0000 @@ -38,6 +38,7 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); extern int ata_qc_issue(struct ata_queued_cmd *qc); +extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/libata-scsi.c linux-2.6.10/drivers/scsi/libata-scsi.c --- linux.vanilla-2.6.10/drivers/scsi/libata-scsi.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/libata-scsi.c 2004-12-29 22:51:25.000000000 +0000 @@ -1294,6 +1294,11 @@ int using_pio = (dev->flags & ATA_DFLAG_PIO); int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + if (!using_pio) + /* Check whether ATAPI DMA is safe */ + if (ata_check_atapi_dma(qc)) + using_pio = 1; + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); qc->complete_fn = atapi_qc_complete; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/megaraid.c linux-2.6.10/drivers/scsi/megaraid.c --- linux.vanilla-2.6.10/drivers/scsi/megaraid.c 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/megaraid.c 2005-01-06 22:16:01.000000000 +0000 @@ -5109,11 +5109,11 @@ */ unregister_chrdev(major, "megadev"); + pci_unregister_driver(&megaraid_pci_driver); + #ifdef CONFIG_PROC_FS remove_proc_entry("megaraid", &proc_root); #endif - - pci_unregister_driver(&megaraid_pci_driver); } module_init(megaraid_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/scsi/nsp32.h linux-2.6.10/drivers/scsi/nsp32.h --- linux.vanilla-2.6.10/drivers/scsi/nsp32.h 2004-12-25 21:15:40.000000000 +0000 +++ linux-2.6.10/drivers/scsi/nsp32.h 2004-12-26 18:53:37.000000000 +0000 @@ -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.10/drivers/scsi/sata_uli.c linux-2.6.10/drivers/scsi/sata_uli.c --- linux.vanilla-2.6.10/drivers/scsi/sata_uli.c 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/drivers/scsi/sata_uli.c 2004-12-29 22:49:56.000000000 +0000 @@ -32,16 +32,18 @@ #include #define DRV_NAME "sata_uli" -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.5" enum { uli_5289 = 0, uli_5287 = 1, + uli_5281 = 2, /* PCI configuration registers */ - ULI_SCR_BASE = 0x90, /* sata0 phy SCR registers */ - ULI_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */ - + ULI5287_BASE = 0x90, /* sata0 phy SCR registers */ + ULI5287_OFFS = 0x10, /* offset from sata0->sata1 phy regs */ + ULI5281_BASE = 0x60, /* sata0 phy SCR registers */ + ULI5281_OFFS = 0x60, /* offset from sata0->sata1 phy regs */ }; static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); @@ -51,6 +53,7 @@ static struct pci_device_id uli_pci_tbl[] = { { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 }, { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 }, + { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 }, { } /* terminate list */ }; @@ -125,33 +128,15 @@ MODULE_DEVICE_TABLE(pci, uli_pci_tbl); MODULE_VERSION(DRV_VERSION); -static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg) +static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) { - unsigned int addr = ULI_SCR_BASE + (4 * sc_reg); - - switch (port_no) { - case 0: - break; - case 1: - addr += ULI_SATA1_OFS; - break; - case 2: - addr += ULI_SATA1_OFS*4; - break; - case 3: - addr += ULI_SATA1_OFS*5; - break; - default: - BUG(); - break; - } - return addr; + return ap->ioaddr.scr_addr + (4 * sc_reg); } static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg); + unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); u32 val; pci_read_config_dword(pdev, cfg_addr, &val); @@ -161,7 +146,7 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr); + unsigned int cfg_addr = get_scr_cfg_addr(ap, scr); pci_write_config_dword(pdev, cfg_addr, val); } @@ -222,9 +207,11 @@ rc = -ENOMEM; goto err_out_regions; } - + switch (board_idx) { case uli_5287: + probe_ent->port[0].scr_addr = ULI5287_BASE; + probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS; probe_ent->n_ports = 4; probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8; @@ -232,19 +219,27 @@ probe_ent->port[2].ctl_addr = (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4; probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16; + probe_ent->port[2].scr_addr = ULI5287_BASE + ULI5287_OFFS*4; probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8; probe_ent->port[3].altstatus_addr = probe_ent->port[3].ctl_addr = (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4; probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24; + probe_ent->port[3].scr_addr = ULI5287_BASE + ULI5287_OFFS*5; ata_std_ports(&probe_ent->port[2]); ata_std_ports(&probe_ent->port[3]); break; case uli_5289: - /* do nothing; ata_pci_init_native_mode did it all */ + probe_ent->port[0].scr_addr = ULI5287_BASE; + probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS; + break; + + case uli_5281: + probe_ent->port[0].scr_addr = ULI5281_BASE; + probe_ent->port[1].scr_addr = ULI5281_BASE + ULI5281_OFFS; break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/usb/media/Kconfig linux-2.6.10/drivers/usb/media/Kconfig --- linux.vanilla-2.6.10/drivers/usb/media/Kconfig 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/drivers/usb/media/Kconfig 2004-12-26 17:14:49.000000000 +0000 @@ -175,3 +175,39 @@ To compile this driver as a module, choose M here: the module will be called w9968cf. + +config USB_PWC + tristate "USB Philips Cameras" + depends on USB && VIDEO_DEV + ---help--- + Say Y or M here if you want to use one of these Philips & OEM + webcams: + * Philips PCA645, PCA646 + * Philips PCVC675, PCVC680, PCVC690 + * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 + * Askey VC010 + * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' + and 'Orbit'/'Sphere' + * Samsung MPC-C10, MPC-C30 + * Creative Webcam 5, Pro Ex + * SOTEC Afina Eye + * Visionite VCS-UC300, VCS-UM100 + + The PCA635, PCVC665 and PCVC720/20 are not supported by this driver + and never will be, but the 665 and 720/20 are supported by other + drivers. + + See for more information and + installation instructions. + + The built-in microphone is enabled by selecting USB Audio support. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Character Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + at . + + To compile this driver as a module, choose M here: the + module will be called pwc. + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/usb/media/Makefile linux-2.6.10/drivers/usb/media/Makefile --- linux.vanilla-2.6.10/drivers/usb/media/Makefile 2004-12-25 21:14:41.000000000 +0000 +++ linux-2.6.10/drivers/usb/media/Makefile 2004-12-26 17:14:49.000000000 +0000 @@ -14,3 +14,4 @@ obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o +obj-$(CONFIG_USB_PWC) += pwc/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/drivers/usb/media/pwc/ChangeLog linux-2.6.10/drivers/usb/media/pwc/ChangeLog --- linux.vanilla-2.6.10/drivers/usb/media/pwc/ChangeLog 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/ChangeLog 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/Makefile linux-2.6.10/drivers/usb/media/pwc/Makefile --- linux.vanilla-2.6.10/drivers/usb/media/pwc/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/Makefile 2005-01-04 17:38:17.000000000 +0000 @@ -0,0 +1,20 @@ +ifneq ($(KERNELRELEASE),) + +pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o + +obj-$(CONFIG_USB_PWC) += 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.10/drivers/usb/media/pwc/pwc-ctrl.c linux-2.6.10/drivers/usb/media/pwc/pwc-ctrl.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-ctrl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-ctrl.c 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-dec1.c linux-2.6.10/drivers/usb/media/pwc/pwc-dec1.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-dec1.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-dec1.c 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-dec1.h linux-2.6.10/drivers/usb/media/pwc/pwc-dec1.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-dec1.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-dec1.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-dec23.c linux-2.6.10/drivers/usb/media/pwc/pwc-dec23.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-dec23.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-dec23.c 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-dec23.h linux-2.6.10/drivers/usb/media/pwc/pwc-dec23.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-dec23.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-dec23.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc.h linux-2.6.10/drivers/usb/media/pwc/pwc.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-if.c linux-2.6.10/drivers/usb/media/pwc/pwc-if.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-if.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-if.c 2005-01-06 15:56:28.000000000 +0000 @@ -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_kill_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 = vmalloc_to_pfn((void *)pos); + if (remap_pfn_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.10/drivers/usb/media/pwc/pwc-ioctl.h linux-2.6.10/drivers/usb/media/pwc/pwc-ioctl.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-ioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-ioctl.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-kiara.c linux-2.6.10/drivers/usb/media/pwc/pwc-kiara.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-kiara.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-kiara.c 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-kiara.h linux-2.6.10/drivers/usb/media/pwc/pwc-kiara.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-kiara.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-kiara.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-misc.c linux-2.6.10/drivers/usb/media/pwc/pwc-misc.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-misc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-misc.c 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-nala.h linux-2.6.10/drivers/usb/media/pwc/pwc-nala.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-nala.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-nala.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-timon.c linux-2.6.10/drivers/usb/media/pwc/pwc-timon.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-timon.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-timon.c 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-timon.h linux-2.6.10/drivers/usb/media/pwc/pwc-timon.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-timon.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-timon.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-uncompress.c linux-2.6.10/drivers/usb/media/pwc/pwc-uncompress.c --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-uncompress.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-uncompress.c 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/pwc-uncompress.h linux-2.6.10/drivers/usb/media/pwc/pwc-uncompress.h --- linux.vanilla-2.6.10/drivers/usb/media/pwc/pwc-uncompress.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/pwc-uncompress.h 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/drivers/usb/media/pwc/philips.txt linux-2.6.10/drivers/usb/media/pwc/philips.txt --- linux.vanilla-2.6.10/drivers/usb/media/pwc/philips.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/drivers/usb/media/pwc/philips.txt 2004-12-26 17:14:49.000000000 +0000 @@ -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.10/fs/buffer.c linux-2.6.10/fs/buffer.c --- linux.vanilla-2.6.10/fs/buffer.c 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/fs/buffer.c 2004-12-26 23:01:43.000000000 +0000 @@ -422,6 +422,7 @@ struct buffer_head *bh; struct buffer_head *head; struct page *page; + int all_mapped = 1; index = block >> (PAGE_CACHE_SHIFT - bd_inode->i_blkbits); page = find_get_page(bd_mapping, index); @@ -439,14 +440,23 @@ get_bh(bh); goto out_unlock; } + if (!buffer_mapped(bh)) + all_mapped = 0; bh = bh->b_this_page; } while (bh != head); - printk("__find_get_block_slow() failed. " - "block=%llu, b_blocknr=%llu\n", - (unsigned long long)block, (unsigned long long)bh->b_blocknr); - printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size); - printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits); + /* we might be here because some of the buffers on this page are + * not mapped. This is due to various races between + * file io on the block device and getblk. It gets dealt with + * elsewhere, don't buffer_error if we had some unmapped buffers + */ + if (all_mapped) { + printk("__find_get_block_slow() failed. " + "block=%llu, b_blocknr=%llu\n", + (unsigned long long)block, (unsigned long long)bh->b_blocknr); + printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size); + printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits); + } out_unlock: spin_unlock(&bd_mapping->private_lock); page_cache_release(page); @@ -1089,18 +1099,16 @@ { struct buffer_head *head = page_buffers(page); struct buffer_head *bh = head; - unsigned int b_state; - - b_state = 1 << BH_Mapped; - if (PageUptodate(page)) - b_state |= 1 << BH_Uptodate; + int uptodate = PageUptodate(page); do { - if (!(bh->b_state & (1 << BH_Mapped))) { + if (!buffer_mapped(bh)) { init_buffer(bh, NULL, NULL); bh->b_bdev = bdev; bh->b_blocknr = block; - bh->b_state = b_state; + if (uptodate) + set_buffer_uptodate(bh); + set_buffer_mapped(bh); } block++; bh = bh->b_this_page; @@ -1129,8 +1137,10 @@ if (page_has_buffers(page)) { bh = page_buffers(page); - if (bh->b_size == size) + if (bh->b_size == size) { + init_page_buffers(page, bdev, block, size); return page; + } if (!try_to_free_buffers(page)) goto failed; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/fs/coda/upcall.c linux-2.6.10/fs/coda/upcall.c --- linux.vanilla-2.6.10/fs/coda/upcall.c 2004-12-25 21:15:14.000000000 +0000 +++ linux-2.6.10/fs/coda/upcall.c 2005-01-07 15:42:06.000000000 +0000 @@ -550,7 +550,7 @@ UPARG(CODA_IOCTL); /* build packet for Venus */ - if (data->vi.in_size > VC_MAXDATASIZE) { + if (data->vi.in_size > VC_MAXDATASIZE || data->vi.in_size < 0) { error = -EINVAL; goto exit; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/fs/exec.c linux-2.6.10/fs/exec.c --- linux.vanilla-2.6.10/fs/exec.c 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/fs/exec.c 2005-01-07 16:33:04.844056400 +0000 @@ -57,6 +57,9 @@ 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; @@ -337,6 +340,8 @@ force_sig(SIGKILL, current); } +#define EXTRA_STACK_VM_PAGES 20 /* random */ + int setup_arg_pages(struct linux_binprm *bprm, int executable_stack) { unsigned long stack_base; @@ -374,15 +379,15 @@ memmove(to, to + offset, PAGE_SIZE - offset); kunmap(bprm->page[j - 1]); - /* Adjust bprm->p to point to the end of the strings. */ - bprm->p = PAGE_SIZE * i - offset; - /* Limit stack size to 1GB */ stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max; if (stack_base > (1 << 30)) stack_base = 1 << 30; stack_base = PAGE_ALIGN(STACK_TOP - stack_base); + /* Adjust bprm->p to point to the end of the strings. */ + bprm->p = stack_base + PAGE_SIZE * i - offset; + mm->arg_start = stack_base; arg_size = i << PAGE_SHIFT; @@ -391,11 +396,13 @@ bprm->page[i++] = NULL; #else stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE; - mm->arg_start = bprm->p + stack_base; + bprm->p += stack_base; + mm->arg_start = bprm->p; arg_size = STACK_TOP - (PAGE_MASK & (unsigned long) mm->arg_start); #endif - bprm->p += stack_base; + arg_size += EXTRA_STACK_VM_PAGES * PAGE_SIZE; + if (bprm->loader) bprm->loader += stack_base; bprm->exec += stack_base; @@ -416,11 +423,10 @@ mpnt->vm_mm = mm; #ifdef CONFIG_STACK_GROWSUP mpnt->vm_start = stack_base; - mpnt->vm_end = PAGE_MASK & - (PAGE_SIZE - 1 + (unsigned long) bprm->p); + mpnt->vm_end = stack_base + arg_size; #else - mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_end = STACK_TOP; + mpnt->vm_start = mpnt->vm_end - arg_size; #endif /* Adjust stack execute permissions; explicitly enable * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X @@ -832,6 +838,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 == '/') @@ -849,7 +858,7 @@ permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) || (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { suid_keys(current); - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; } /* An exec changes our domain. We are no longer part of the thread @@ -1373,6 +1382,8 @@ struct inode * inode; struct file * file; int retval = 0; + int fsuid = current->fsuid; + int flag = 0; binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) @@ -1382,6 +1393,16 @@ 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; @@ -1398,7 +1419,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; @@ -1423,6 +1444,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.10/fs/openpromfs/inode.c linux-2.6.10/fs/openpromfs/inode.c --- linux.vanilla-2.6.10/fs/openpromfs/inode.c 2004-12-25 21:15:13.000000000 +0000 +++ linux-2.6.10/fs/openpromfs/inode.c 2005-01-06 22:06:50.000000000 +0000 @@ -94,8 +94,6 @@ openprom_property *op; char buffer[64]; - if (*ppos >= 0xffffff || count >= 0xffffff) - return -EINVAL; if (!filp->private_data) { node = nodes[(u16)((long)inode->u.generic_ip)].node; i = ((u32)(long)inode->u.generic_ip) >> 16; @@ -168,6 +166,8 @@ op = (openprom_property *)filp->private_data; if (!count || !(op->len || (op->flag & OPP_ASCIIZ))) return 0; + if (*ppos >= 0xffffff || count >= 0xffffff) + return -EINVAL; if (op->flag & OPP_STRINGLIST) { for (k = 0, p = op->value; p < op->value + op->len; p++) if (!*p) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/fs/proc/base.c linux-2.6.10/fs/proc/base.c --- linux.vanilla-2.6.10/fs/proc/base.c 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/fs/proc/base.c 2004-12-26 19:05:57.000000000 +0000 @@ -308,7 +308,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; @@ -925,7 +925,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.10/fs/smbfs/proc.c linux-2.6.10/fs/smbfs/proc.c --- linux.vanilla-2.6.10/fs/smbfs/proc.c 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/fs/smbfs/proc.c 2004-12-26 23:03:13.000000000 +0000 @@ -1427,9 +1427,9 @@ * So we must first calculate the amount of padding used by the server. */ data_off -= hdrlen; - if (data_off > SMB_READX_MAX_PAD) { - PARANOIA("offset is larger than max pad!\n"); - PARANOIA("%d > %d\n", data_off, SMB_READX_MAX_PAD); + if (data_off > SMB_READX_MAX_PAD || data_off < 0) { + PARANOIA("offset is larger than SMB_READX_MAX_PAD or negative!\n"); + PARANOIA("%d > %d || %d < 0\n", data_off, SMB_READX_MAX_PAD, data_off); req->rq_rlen = req->rq_bufsize + 1; return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/fs/smbfs/request.c linux-2.6.10/fs/smbfs/request.c --- linux.vanilla-2.6.10/fs/smbfs/request.c 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/fs/smbfs/request.c 2004-12-26 23:06:24.000000000 +0000 @@ -588,8 +588,18 @@ data_count = WVAL(inbuf, smb_drcnt); /* Modify offset for the split header/buffer we use */ - data_offset -= hdrlen; - parm_offset -= hdrlen; + if (data_count || data_offset) { + if (unlikely(data_offset < hdrlen)) + goto out_bad_data; + else + data_offset -= hdrlen; + } + if (parm_count || parm_offset) { + if (unlikely(parm_offset < hdrlen)) + goto out_bad_parm; + else + parm_offset -= hdrlen; + } if (parm_count == parm_tot && data_count == data_tot) { /* @@ -600,18 +610,22 @@ * response that fits. */ VERBOSE("single trans2 response " - "dcnt=%d, pcnt=%d, doff=%d, poff=%d\n", + "dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", data_count, parm_count, data_offset, parm_offset); req->rq_ldata = data_count; req->rq_lparm = parm_count; req->rq_data = req->rq_buffer + data_offset; req->rq_parm = req->rq_buffer + parm_offset; + if (unlikely(parm_offset + parm_count > req->rq_rlen)) + goto out_bad_parm; + if (unlikely(data_offset + data_count > req->rq_rlen)) + goto out_bad_data; return 0; } VERBOSE("multi trans2 response " - "frag=%d, dcnt=%d, pcnt=%d, doff=%d, poff=%d\n", + "frag=%d, dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", req->rq_fragment, data_count, parm_count, data_offset, parm_offset); @@ -638,13 +652,15 @@ req->rq_parm = req->rq_trans2buffer; req->rq_data = req->rq_trans2buffer + parm_tot; - } else if (req->rq_total_data < data_tot || - req->rq_total_parm < parm_tot) + } else if (unlikely(req->rq_total_data < data_tot || + req->rq_total_parm < parm_tot)) goto out_data_grew; - if (parm_disp + parm_count > req->rq_total_parm) + if (unlikely(parm_disp + parm_count > req->rq_total_parm || + parm_offset + parm_count > req->rq_rlen)) goto out_bad_parm; - if (data_disp + data_count > req->rq_total_data) + if (unlikely(data_disp + data_count > req->rq_total_data || + data_offset + data_count > req->rq_rlen)) goto out_bad_data; inbuf = req->rq_buffer; @@ -666,10 +682,9 @@ return 1; out_too_long: - printk(KERN_ERR "smb_trans2: data/param too long, data=%d, parm=%d\n", + printk(KERN_ERR "smb_trans2: data/param too long, data=%u, parm=%u\n", data_tot, parm_tot); - req->rq_errno = -EIO; - goto out; + goto out_EIO; out_no_mem: printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n", req->rq_trans2bufsize); @@ -677,16 +692,15 @@ goto out; out_data_grew: printk(KERN_ERR "smb_trans2: data/params grew!\n"); - req->rq_errno = -EIO; - goto out; + goto out_EIO; out_bad_parm: - printk(KERN_ERR "smb_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n", - parm_disp, parm_count, parm_tot); - req->rq_errno = -EIO; - goto out; + printk(KERN_ERR "smb_trans2: invalid parms, disp=%u, cnt=%u, tot=%u, ofs=%u\n", + parm_disp, parm_count, parm_tot, parm_offset); + goto out_EIO; out_bad_data: - printk(KERN_ERR "smb_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n", - data_disp, data_count, data_tot); + printk(KERN_ERR "smb_trans2: invalid data, disp=%u, cnt=%u, tot=%u, ofs=%u\n", + data_disp, data_count, data_tot, data_offset); +out_EIO: req->rq_errno = -EIO; out: return req->rq_errno; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/fs/xfs/linux-2.6/xfs_ioctl.c linux-2.6.10/fs/xfs/linux-2.6/xfs_ioctl.c --- linux.vanilla-2.6.10/fs/xfs/linux-2.6/xfs_ioctl.c 2004-12-25 21:15:41.000000000 +0000 +++ linux-2.6.10/fs/xfs/linux-2.6/xfs_ioctl.c 2005-01-07 15:43:19.815849664 +0000 @@ -508,6 +508,10 @@ if (error) return -error; + if(am_hreq.opcount > 1024) { + VN_RELE(vp); + return -XFS_ERROR(ENOMEM); + } size = am_hreq.opcount * sizeof(attr_multiop_t); ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL); if (!ops) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/asm-i386/agp.h linux-2.6.10/include/asm-i386/agp.h --- linux.vanilla-2.6.10/include/asm-i386/agp.h 2004-12-25 21:13:51.000000000 +0000 +++ linux-2.6.10/include/asm-i386/agp.h 2005-01-03 18:37:16.000000000 +0000 @@ -12,8 +12,8 @@ * data corruption on some CPUs. */ -#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) -#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL) +int map_page_into_agp(struct page *page); +int unmap_page_from_agp(struct page *page); #define flush_agp_mappings() global_flush_tlb() /* Could use CLFLUSH here if the cpu supports it. But then it would diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/asm-i386/ide.h linux-2.6.10/include/asm-i386/ide.h --- linux.vanilla-2.6.10/include/asm-i386/ide.h 2004-12-25 21:13:51.000000000 +0000 +++ linux-2.6.10/include/asm-i386/ide.h 2004-12-29 22:34:05.000000000 +0000 @@ -41,16 +41,20 @@ static __inline__ unsigned long ide_default_io_base(int index) { + if(pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) { + switch(index) { + case 2: return 0x1e8; + case 3: return 0x168; + case 4: return 0x1e0; + case 5: return 0x160; + } + } switch (index) { case 0: return 0x1f0; case 1: return 0x170; - case 2: return 0x1e8; - case 3: return 0x168; - case 4: return 0x1e0; - case 5: return 0x160; default: return 0; - } + } } #define IDE_ARCH_OBSOLETE_INIT diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/asm-i386/param.h linux-2.6.10/include/asm-i386/param.h --- linux.vanilla-2.6.10/include/asm-i386/param.h 2004-12-25 21:13:52.000000000 +0000 +++ linux-2.6.10/include/asm-i386/param.h 2004-12-26 17:08:01.000000000 +0000 @@ -1,8 +1,10 @@ #ifndef _ASMi386_PARAM_H #define _ASMi386_PARAM_H +#include + #ifdef __KERNEL__ -# define HZ 1000 /* Internal kernel timer frequency */ +# define HZ (CONFIG_X86_HZ) # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/asm-sh/mpc1211/keyboard.h linux-2.6.10/include/asm-sh/mpc1211/keyboard.h --- linux.vanilla-2.6.10/include/asm-sh/mpc1211/keyboard.h 2004-12-25 21:14:04.000000000 +0000 +++ linux-2.6.10/include/asm-sh/mpc1211/keyboard.h 2005-01-06 22:27:31.000000000 +0000 @@ -57,7 +57,7 @@ #define AUX_IRQ 12 #define aux_request_irq(hand, dev_id) \ - request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS2 Mouse", dev_id) #define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/asm-sh64/keyboard.h linux-2.6.10/include/asm-sh64/keyboard.h --- linux.vanilla-2.6.10/include/asm-sh64/keyboard.h 2004-12-25 21:13:51.000000000 +0000 +++ linux-2.6.10/include/asm-sh64/keyboard.h 2005-01-06 22:27:31.000000000 +0000 @@ -65,7 +65,7 @@ #endif #define aux_request_irq(hand, dev_id) \ - request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS2 Mouse", dev_id) #define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/asm-x86_64/agp.h linux-2.6.10/include/asm-x86_64/agp.h --- linux.vanilla-2.6.10/include/asm-x86_64/agp.h 2004-12-25 21:14:01.000000000 +0000 +++ linux-2.6.10/include/asm-x86_64/agp.h 2005-01-03 18:37:16.000000000 +0000 @@ -10,9 +10,8 @@ * with different cachability attributes for the same page. */ -#define map_page_into_agp(page) \ - change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) -#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL) +int map_page_into_agp(struct page *page); +int unmap_page_from_agp(struct page *page); #define flush_agp_mappings() global_flush_tlb() /* Could use CLFLUSH here if the cpu supports it. But then it would diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/binfmts.h linux-2.6.10/include/linux/binfmts.h --- linux.vanilla-2.6.10/include/linux/binfmts.h 2004-12-25 21:13:56.000000000 +0000 +++ linux-2.6.10/include/linux/binfmts.h 2004-12-26 18:56:02.000000000 +0000 @@ -69,6 +69,11 @@ extern int search_binary_handler(struct linux_binprm *,struct pt_regs *); extern int flush_old_exec(struct linux_binprm * bprm); +extern int suid_dumpable; +#define SUID_DUMP_DISABLE 0 /* No setuid dumping */ +#define SUID_DUMP_USER 1 /* Dump as user of process */ +#define SUID_DUMP_ROOT 2 /* Dump as root */ + /* Stack area protections */ #define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */ #define EXSTACK_DISABLE_X 1 /* Disable executable stacks */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/edd.h linux-2.6.10/include/linux/edd.h --- linux.vanilla-2.6.10/include/linux/edd.h 2004-12-25 21:13:59.000000000 +0000 +++ linux-2.6.10/include/linux/edd.h 2004-12-26 17:06:29.000000000 +0000 @@ -49,6 +49,10 @@ #define EDD_MBR_SIG_MAX 16 /* max number of signatures to store */ #define EDD_MBR_SIG_NR_BUF 0x1ea /* addr of number of MBR signtaures at EDD_MBR_SIG_BUF in boot_params - treat this as 1 byte */ +#define EDD_CL_EQUALS 0x3d646465 /* "edd=" */ +#define EDD_CL_OFF 0x666f /* "of" for off */ +#define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */ + #ifndef __ASSEMBLY__ #define EDD_EXT_FIXED_DISK_ACCESS (1 << 0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/ide.h linux-2.6.10/include/linux/ide.h --- linux.vanilla-2.6.10/include/linux/ide.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/linux/ide.h 2004-12-26 22:43:21.000000000 +0000 @@ -754,6 +754,7 @@ unsigned int max_failures; /* maximum allowed failure count */ u64 capacity64; /* total number of sectors */ + u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */ int lun; /* logical unit */ int crc_count; /* crc counter to reduce drive speed */ @@ -768,6 +769,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 */ @@ -775,6 +777,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 */ @@ -830,6 +833,9 @@ // 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 */ #endif void (*ata_input_data)(ide_drive_t *, void *, u32); @@ -838,9 +844,9 @@ void (*atapi_input_bytes)(ide_drive_t *, void *, u32); void (*atapi_output_bytes)(ide_drive_t *, void *, u32); - int (*dma_setup)(ide_drive_t *); - void (*dma_exec_cmd)(ide_drive_t *, u8); - void (*dma_start)(ide_drive_t *); + int (*ide_dma_setup)(ide_drive_t *); + void (*ide_dma_exec_cmd)(ide_drive_t *, u8); + void (*ide_dma_start)(ide_drive_t *); int (*ide_dma_end)(ide_drive_t *drive); int (*ide_dma_check)(ide_drive_t *drive); int (*ide_dma_on)(ide_drive_t *drive); @@ -901,7 +907,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 */ @@ -912,6 +920,7 @@ unsigned no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */ unsigned auto_poll : 1; /* supports nop auto-poll */ unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */ + unsigned polling : 1; /* doing a polled command ignore irqs */ struct device gendev; struct semaphore gendev_rel_sem; /* To deal with device release() */ @@ -1004,6 +1013,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 */ @@ -1020,7 +1034,7 @@ extern void proc_ide_create(void); extern void proc_ide_destroy(void); extern void create_proc_ide_interfaces(void); -void destroy_proc_ide_interface(ide_hwif_t *); +extern void destroy_proc_ide_interface(ide_hwif_t *); 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 *); read_proc_t proc_ide_read_capacity; @@ -1133,6 +1147,7 @@ extern int noautodma; extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs); +extern int ide_end_dequeued_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs); /* * This is used on exit from the driver to designate the next irq handler @@ -1384,9 +1399,11 @@ extern void ide_pci_unregister_driver(struct pci_driver *driver); void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *); 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); @@ -1487,11 +1504,12 @@ 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 int ide_unregister_hwif(ide_hwif_t *hwif); +extern int __ide_unregister_hwif(ide_hwif_t *hwif); -void ide_undecoded_slave(ide_hwif_t *); +extern void ide_undecoded_slave(ide_hwif_t *); -int probe_hwif_init_with_fixup(ide_hwif_t *, void (*)(ide_hwif_t *)); +extern int probe_hwif_init_with_fixup(ide_hwif_t *, void (*)(ide_hwif_t *)); extern int probe_hwif_init(ide_hwif_t *); static inline void *ide_get_hwifdata (ide_hwif_t * hwif) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/irq.h linux-2.6.10/include/linux/irq.h --- linux.vanilla-2.6.10/include/linux/irq.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/linux/irq.h 2004-12-26 23:26:15.000000000 +0000 @@ -82,7 +82,7 @@ extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action); extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); -extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret); +extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret, struct pt_regs *regs); extern void report_bad_irq(unsigned int irq, irq_desc_t *desc, int action_ret); extern int can_request_irq(unsigned int irq, unsigned long irqflags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/isicom.h linux-2.6.10/include/linux/isicom.h --- linux.vanilla-2.6.10/include/linux/isicom.h 2004-12-25 21:13:59.000000000 +0000 +++ linux-2.6.10/include/linux/isicom.h 2005-01-06 18:28:29.000000000 +0000 @@ -125,179 +125,6 @@ #define ISI_TXOK 0x0001 -struct isi_board { - unsigned short base; - unsigned char irq; - unsigned char port_count; - unsigned short status; - unsigned short port_status; /* each bit represents a single port */ - unsigned short shift_count; - struct isi_port * ports; - signed char count; - unsigned char isa; -}; - -struct isi_port { - unsigned short magic; - unsigned int flags; - int count; - int blocked_open; - int close_delay; - unsigned short channel; - unsigned short status; - unsigned short closing_wait; - struct isi_board * card; - struct tty_struct * tty; - wait_queue_head_t close_wait; - wait_queue_head_t open_wait; - struct work_struct hangup_tq; - struct work_struct bh_tqueue; - unsigned char * xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; -}; - - -/* - * ISI Card specific ops ... - */ - -static inline void raise_dtr(struct isi_port * port) -{ - struct isi_board * card = port->card; - unsigned short base = card->base; - unsigned char channel = port->channel; - short wait=400; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr.\n"); - return; - } -#ifdef ISICOM_DEBUG_DTR_RTS - printk(KERN_DEBUG "ISICOM: raise_dtr.\n"); -#endif - outw(0x8000 | (channel << card->shift_count) | 0x02 , base); - outw(0x0504, base); - InterruptTheCard(base); - port->status |= ISI_DTR; -} - -static inline void drop_dtr(struct isi_port * port) -{ - struct isi_board * card = port->card; - unsigned short base = card->base; - unsigned char channel = port->channel; - short wait=400; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr.\n"); - return; - } -#ifdef ISICOM_DEBUG_DTR_RTS - printk(KERN_DEBUG "ISICOM: drop_dtr.\n"); -#endif - outw(0x8000 | (channel << card->shift_count) | 0x02 , base); - outw(0x0404, base); - InterruptTheCard(base); - port->status &= ~ISI_DTR; -} -static inline void raise_rts(struct isi_port * port) -{ - struct isi_board * card = port->card; - unsigned short base = card->base; - unsigned char channel = port->channel; - short wait=400; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - printk(KERN_WARNING "ISICOM: Card found busy in raise_rts.\n"); - return; - } -#ifdef ISICOM_DEBUG_DTR_RTS - printk(KERN_DEBUG "ISICOM: raise_rts.\n"); -#endif - outw(0x8000 | (channel << card->shift_count) | 0x02 , base); - outw(0x0a04, base); - InterruptTheCard(base); - port->status |= ISI_RTS; -} -static inline void drop_rts(struct isi_port * port) -{ - struct isi_board * card = port->card; - unsigned short base = card->base; - unsigned char channel = port->channel; - short wait=400; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - printk(KERN_WARNING "ISICOM: Card found busy in drop_rts.\n"); - return; - } -#ifdef ISICOM_DEBUG_DTR_RTS - printk(KERN_DEBUG "ISICOM: drop_rts.\n"); -#endif - outw(0x8000 | (channel << card->shift_count) | 0x02 , base); - outw(0x0804, base); - InterruptTheCard(base); - port->status &= ~ISI_RTS; -} -static inline void raise_dtr_rts(struct isi_port * port) -{ - struct isi_board * card = port->card; - unsigned short base = card->base; - unsigned char channel = port->channel; - short wait=400; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr_rts.\n"); - return; - } -#ifdef ISICOM_DEBUG_DTR_RTS - printk(KERN_DEBUG "ISICOM: raise_dtr_rts.\n"); -#endif - outw(0x8000 | (channel << card->shift_count) | 0x02 , base); - outw(0x0f04, base); - InterruptTheCard(base); - port->status |= (ISI_DTR | ISI_RTS); -} -static inline void drop_dtr_rts(struct isi_port * port) -{ - struct isi_board * card = port->card; - unsigned short base = card->base; - unsigned char channel = port->channel; - short wait=400; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr_rts.\n"); - return; - } -#ifdef ISICOM_DEBUG_DTR_RTS - printk(KERN_DEBUG "ISICOM: drop_dtr_rts.\n"); -#endif - outw(0x8000 | (channel << card->shift_count) | 0x02 , base); - outw(0x0c04, base); - InterruptTheCard(base); - port->status &= ~(ISI_RTS | ISI_DTR); -} - -static inline void kill_queue(struct isi_port * port, short queue) -{ - struct isi_board * card = port->card; - unsigned short base = card->base; - unsigned char channel = port->channel; - short wait=400; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - printk(KERN_WARNING "ISICOM: Card found busy in kill_queue.\n"); - return; - } -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: kill_queue 0x%x.\n", queue); -#endif - outw(0x8000 | (channel << card->shift_count) | 0x02 , base); - outw((queue << 8) | 0x06, base); - InterruptTheCard(base); -} - #endif /* __KERNEL__ */ #endif /* ISICOM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/libata.h linux-2.6.10/include/linux/libata.h --- linux.vanilla-2.6.10/include/linux/libata.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/linux/libata.h 2004-12-29 22:51:25.000000000 +0000 @@ -339,6 +339,8 @@ void (*phy_reset) (struct ata_port *ap); void (*post_set_mode) (struct ata_port *ap); + int (*check_atapi_dma) (struct ata_queued_cmd *qc); + void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/mm.h linux-2.6.10/include/linux/mm.h --- linux.vanilla-2.6.10/include/linux/mm.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/linux/mm.h 2005-01-07 15:37:37.178938392 +0000 @@ -703,6 +703,7 @@ extern int do_munmap(struct mm_struct *, unsigned long, size_t); +extern unsigned long __do_brk(unsigned long, unsigned long); extern unsigned long do_brk(unsigned long, unsigned long); /* filemap.c */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/pci_ids.h linux-2.6.10/include/linux/pci_ids.h --- linux.vanilla-2.6.10/include/linux/pci_ids.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/linux/pci_ids.h 2005-01-03 18:36:55.000000000 +0000 @@ -344,7 +344,9 @@ #define PCI_DEVICE_ID_ATI_RS300_200 0x5833 /* ATI IXP Chipset */ #define PCI_DEVICE_ID_ATI_IXP_IDE 0x4349 -#define PCI_DEVICE_ID_ATI_IXP2_IDE 0x4369 /* True name not yet sure */ +#define PCI_DEVICE_ID_ATI_IXP_IDE2 0x4369 /* True name not yet sure */ +#define PCI_DEVICE_ID_ATI_IXP_IDE3 0x4376 /* True name not yet sure */ +#define PCI_DEVICE_ID_ATI_IXP_IDE4 0x4379 /* True name not yet sure */ #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 @@ -1017,6 +1019,7 @@ #define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 #define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1543 0x1543 #define PCI_DEVICE_ID_AL_M1563 0x1563 #define PCI_DEVICE_ID_AL_M1621 0x1621 #define PCI_DEVICE_ID_AL_M1631 0x1631 @@ -1026,6 +1029,9 @@ #define PCI_DEVICE_ID_AL_M1647 0x1647 #define PCI_DEVICE_ID_AL_M1651 0x1651 #define PCI_DEVICE_ID_AL_M1671 0x1671 +#define PCI_DEVICE_ID_AL_M1681 0x1681 +#define PCI_DEVICE_ID_AL_M1683 0x1683 +#define PCI_DEVICE_ID_AL_M1689 0x1689 #define PCI_DEVICE_ID_AL_M1543 0x1543 #define PCI_DEVICE_ID_AL_M3307 0x3307 #define PCI_DEVICE_ID_AL_M4803 0x5215 @@ -1631,6 +1637,10 @@ #define PCI_DEVICE_ID_OPTIBASE_VPLEXCC 0x2120 #define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130 +/* Allied Telesyn */ +#define PCI_VENDOR_ID_AT 0x1259 +#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703 + #define PCI_VENDOR_ID_ESS 0x125d #define PCI_DEVICE_ID_ESS_ESS1968 0x1968 #define PCI_DEVICE_ID_ESS_AUDIOPCI 0x1969 @@ -1657,6 +1667,8 @@ #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_8211 0x8211 +#define PCI_DEVICE_ID_ITE_8212 0x8212 #define PCI_DEVICE_ID_ITE_8872 0x8872 #define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 @@ -2225,6 +2237,30 @@ #define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d #define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e #define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f +#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b0 +#define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b1 +#define PCI_DEVICE_ID_INTEL_ICH7_2 0x27c0 +#define PCI_DEVICE_ID_INTEL_ICH7_3 0x27c1 +#define PCI_DEVICE_ID_INTEL_ICH7_4 0x27c2 +#define PCI_DEVICE_ID_INTEL_ICH7_5 0x27c4 +#define PCI_DEVICE_ID_INTEL_ICH7_6 0x27c5 +#define PCI_DEVICE_ID_INTEL_ICH7_7 0x27c8 +#define PCI_DEVICE_ID_INTEL_ICH7_8 0x27c9 +#define PCI_DEVICE_ID_INTEL_ICH7_9 0x27ca +#define PCI_DEVICE_ID_INTEL_ICH7_10 0x27cb +#define PCI_DEVICE_ID_INTEL_ICH7_11 0x27cc +#define PCI_DEVICE_ID_INTEL_ICH7_12 0x27d0 +#define PCI_DEVICE_ID_INTEL_ICH7_13 0x27d2 +#define PCI_DEVICE_ID_INTEL_ICH7_14 0x27d4 +#define PCI_DEVICE_ID_INTEL_ICH7_15 0x27d6 +#define PCI_DEVICE_ID_INTEL_ICH7_16 0x27d8 +#define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da +#define PCI_DEVICE_ID_INTEL_ICH7_18 0x27dc +#define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd +#define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de +#define PCI_DEVICE_ID_INTEL_ICH7_21 0x27df +#define PCI_DEVICE_ID_INTEL_ICH7_22 0x27e0 +#define PCI_DEVICE_ID_INTEL_ICH7_23 0x27e2 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 @@ -2364,3 +2400,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.10/include/linux/sched.h linux-2.6.10/include/linux/sched.h --- linux.vanilla-2.6.10/include/linux/sched.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/linux/sched.h 2004-12-26 18:58:11.000000000 +0000 @@ -231,7 +231,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.10/include/linux/sem.h linux-2.6.10/include/linux/sem.h --- linux.vanilla-2.6.10/include/linux/sem.h 2004-12-25 21:13:55.000000000 +0000 +++ linux-2.6.10/include/linux/sem.h 2004-12-26 17:04:59.000000000 +0000 @@ -109,6 +109,7 @@ int id; /* internal sem id */ struct sembuf * sops; /* array of pending operations */ int nsops; /* number of operations */ + int alter; /* does the operation alter the array? */ }; /* Each task has a list of undo requests. They are executed automatically diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/linux/sysctl.h linux-2.6.10/include/linux/sysctl.h --- linux.vanilla-2.6.10/include/linux/sysctl.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/linux/sysctl.h 2004-12-26 18:58:53.000000000 +0000 @@ -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.10/include/sound/control.h linux-2.6.10/include/sound/control.h --- linux.vanilla-2.6.10/include/sound/control.h 2004-12-25 21:14:05.000000000 +0000 +++ linux-2.6.10/include/sound/control.h 2005-01-06 19:29:28.000000000 +0000 @@ -122,6 +122,10 @@ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn); int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn); +/* for ioctl32 */ +int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control); +int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t *control); + static inline unsigned int snd_ctl_get_ioffnum(snd_kcontrol_t *kctl, snd_ctl_elem_id_t *id) { return id->numid - kctl->id.numid; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/sound/core.h linux-2.6.10/include/sound/core.h --- linux.vanilla-2.6.10/include/sound/core.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/sound/core.h 2005-01-06 19:29:28.000000000 +0000 @@ -307,8 +307,8 @@ #define vfree_nocheck(obj) vfree(obj) #endif char *snd_kmalloc_strdup(const char *string, int flags); -int copy_to_user_fromio(void __user *dst, const void __iomem *src, size_t count); -int copy_from_user_toio(void __iomem *dst, const void __user *src, size_t count); +int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count); +int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count); /* init.c */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/include/sound/pcm.h linux-2.6.10/include/sound/pcm.h --- linux.vanilla-2.6.10/include/sound/pcm.h 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/include/sound/pcm.h 2005-01-06 19:29:28.000000000 +0000 @@ -810,6 +810,7 @@ int snd_pcm_hw_params_choose(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); int snd_pcm_hw_refine(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); +int snd_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream); int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/ipc/sem.c linux-2.6.10/ipc/sem.c --- linux.vanilla-2.6.10/ipc/sem.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/ipc/sem.c 2004-12-26 17:04:12.000000000 +0000 @@ -358,8 +358,22 @@ if (error <= 0) { struct sem_queue *n; remove_from_queue(sma,q); - n = q->next; q->status = IN_WAKEUP; + /* + * Continue scanning. The next operation + * that must be checked depends on the type of the + * completed operation: + * - if the operation modified the array, then + * restart from the head of the queue and + * check for threads that might be waiting + * for semaphore values to become 0. + * - if the operation didn't modify the array, + * then just continue. + */ + if (q->alter) + n = sma->sem_pending; + else + n = q->next; wake_up_process(q->sleeper); /* hands-off: q will disappear immediately after * writing q->status. @@ -1119,8 +1133,11 @@ goto out_unlock_free; error = try_atomic_semop (sma, sops, nsops, un, current->tgid); - if (error <= 0) - goto update; + if (error <= 0) { + if (alter && error == 0) + update_queue (sma); + goto out_unlock_free; + } /* We need to sleep on this operation, so we put the current * task into the pending queue and go to sleep. @@ -1132,6 +1149,7 @@ queue.undo = un; queue.pid = current->tgid; queue.id = semid; + queue.alter = alter; if (alter) append_to_queue(sma ,&queue); else @@ -1183,9 +1201,6 @@ remove_from_queue(sma,&queue); goto out_unlock_free; -update: - if (alter) - update_queue (sma); out_unlock_free: sem_unlock(sma); out_free: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/kernel/exit.c linux-2.6.10/kernel/exit.c --- linux.vanilla-2.6.10/kernel/exit.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/kernel/exit.c 2005-01-04 18:45:27.000000000 +0000 @@ -332,7 +332,9 @@ exit_mm(current); set_special_pids(1, 1); + down(&tty_sem); current->signal->tty = NULL; + up(&tty_sem); /* Block and flush all signals */ sigfillset(&blocked); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/kernel/irq/handle.c linux-2.6.10/kernel/irq/handle.c --- linux.vanilla-2.6.10/kernel/irq/handle.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/kernel/irq/handle.c 2004-12-26 23:20:04.000000000 +0000 @@ -130,7 +130,7 @@ desc->handler->ack(irq); action_ret = handle_IRQ_event(irq, regs, desc->action); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); desc->handler->end(irq); return 1; } @@ -184,7 +184,7 @@ spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); 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.10/kernel/irq/spurious.c linux-2.6.10/kernel/irq/spurious.c --- linux.vanilla-2.6.10/kernel/irq/spurious.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/kernel/irq/spurious.c 2004-12-26 23:26:55.000000000 +0000 @@ -11,6 +11,77 @@ #include #include +static int irqfixup; + +/* + * Recovery handler for misrouted interrupts. + */ + +static 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 @@ -31,7 +102,7 @@ printk(KERN_ERR "irq event %d: bogus return value %x\n", irq, action_ret); } else { - printk(KERN_ERR "irq %d: nobody cared!\n", irq); + printk(KERN_ERR "irq %d: nobody cared (try booting with the \"irqpoll\" option.\n", irq); } dump_stack(); printk(KERN_ERR "handlers:\n"); @@ -55,7 +126,7 @@ } } -void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) +void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret, struct pt_regs *regs) { if (action_ret != IRQ_HANDLED) { desc->irqs_unhandled++; @@ -63,6 +134,15 @@ 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; + ok = misrouted_irq(irq, regs); + if(action_ret == IRQ_NONE) + desc->irqs_unhandled -= ok; + } + } + desc->irq_count++; if (desc->irq_count < 100000) return; @@ -94,3 +174,22 @@ __setup("noirqdebug", noirqdebug_setup); +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); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/kernel/sys.c linux-2.6.10/kernel/sys.c --- linux.vanilla-2.6.10/kernel/sys.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/kernel/sys.c 2005-01-04 18:47:32.000000000 +0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -521,7 +522,7 @@ } if (new_egid != old_egid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } if (rgid != (gid_t) -1 || @@ -552,7 +553,7 @@ { if(old_egid != gid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->gid = current->egid = current->sgid = current->fsgid = gid; @@ -561,7 +562,7 @@ { if(old_egid != gid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->egid = current->fsgid = gid; @@ -592,7 +593,7 @@ if(dumpclear) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->uid = new_ruid; @@ -649,7 +650,7 @@ if (new_euid != old_euid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = current->euid = new_euid; @@ -699,7 +700,7 @@ if (old_euid != uid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = current->euid = uid; @@ -744,7 +745,7 @@ if (euid != (uid_t) -1) { if (euid != current->euid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->euid = euid; @@ -794,7 +795,7 @@ if (egid != (gid_t) -1) { if (egid != current->egid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->egid = egid; @@ -841,7 +842,7 @@ { if (uid != old_fsuid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = uid; @@ -871,7 +872,7 @@ { if (gid != old_fsgid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsgid = gid; @@ -1075,6 +1076,7 @@ if (!thread_group_leader(current)) return -EINVAL; + down(&tty_sem); write_lock_irq(&tasklist_lock); pid = find_pid(PIDTYPE_PGID, current->pid); @@ -1088,6 +1090,7 @@ err = process_group(current); out: write_unlock_irq(&tasklist_lock); + up(&tty_sem); return err; } @@ -1632,7 +1635,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.10/kernel/sysctl.c linux-2.6.10/kernel/sysctl.c --- linux.vanilla-2.6.10/kernel/sysctl.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/kernel/sysctl.c 2004-12-26 18:59:40.000000000 +0000 @@ -59,6 +59,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; @@ -624,6 +625,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.10/MAINTAINERS linux-2.6.10/MAINTAINERS --- linux.vanilla-2.6.10/MAINTAINERS 2004-12-25 21:15:31.000000000 +0000 +++ linux-2.6.10/MAINTAINERS 2004-12-26 17:02:37.000000000 +0000 @@ -663,7 +663,7 @@ DEVICE NUMBER REGISTRY P: Torben Mathiasen M: device@lanana.org -W: http://lanana.org/docs/device-list/index.html +W: http://www.lanana.org/docs/device-list/index.html L: linux-kernel@vger.kernel.org S: Maintained diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/Makefile linux-2.6.10/Makefile --- linux.vanilla-2.6.10/Makefile 2004-12-25 21:15:31.000000000 +0000 +++ linux-2.6.10/Makefile 2005-01-07 16:47:03.891501800 +0000 @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 10 -EXTRAVERSION = -NAME=Woozy Numbat +EXTRAVERSION = -ac6 +NAME=AC # *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.10/mm/mmap.c linux-2.6.10/mm/mmap.c --- linux.vanilla-2.6.10/mm/mmap.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/mm/mmap.c 2005-01-07 15:31:43.000000000 +0000 @@ -145,7 +145,7 @@ goto out; /* Ok, looks good - let it rip. */ - if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) + if (__do_brk(oldbrk, newbrk-oldbrk) != oldbrk) goto out; set_brk: mm->brk = brk; @@ -1742,7 +1742,7 @@ * anonymous maps. eventually we may be able to do some * brk-specific accounting here. */ -unsigned long do_brk(unsigned long addr, unsigned long len) +unsigned long __do_brk(unsigned long addr, unsigned long len) { struct mm_struct * mm = current->mm; struct vm_area_struct * vma, * prev; @@ -1824,7 +1824,19 @@ return addr; } +EXPORT_SYMBOL(__do_brk); + +unsigned long do_brk(unsigned long addr, unsigned long len) +{ + unsigned long ret; + + down_write(¤t->mm->mmap_sem); + ret = __do_brk(addr, len); + up_write(¤t->mm->mmap_sem); +} + EXPORT_SYMBOL(do_brk); + /* Release all mmaps. */ void exit_mmap(struct mm_struct *mm) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/net/802/tr.c linux-2.6.10/net/802/tr.c --- linux.vanilla-2.6.10/net/802/tr.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/net/802/tr.c 2004-12-26 17:02:20.000000000 +0000 @@ -250,10 +250,11 @@ unsigned int hash; struct rif_cache_s *entry; unsigned char *olddata; + unsigned long flags; static const unsigned char mcast_func_addr[] = {0xC0,0x00,0x00,0x04,0x00,0x00}; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Broadcasts are single route as stated in RFC 1042 @@ -322,7 +323,7 @@ else slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); olddata = skb->data; - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); skb_pull(skb, slack); memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); @@ -336,10 +337,11 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) { unsigned int hash, rii_p = 0; + unsigned long flags; struct rif_cache_s *entry; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Firstly see if the entry exists @@ -377,7 +379,7 @@ if(!entry) { printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n"); - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); return; } @@ -419,7 +421,7 @@ } entry->last_used=jiffies; } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); } /* @@ -429,9 +431,9 @@ static void rif_check_expire(unsigned long dummy) { int i; - unsigned long next_interval = jiffies + sysctl_tr_rif_timeout/2; + unsigned long flags, next_interval = jiffies + sysctl_tr_rif_timeout/2; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); for(i =0; i < RIF_TABLE_SIZE; i++) { struct rif_cache_s *entry, **pentry; @@ -453,7 +455,7 @@ } } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); mod_timer(&rif_timer, next_interval); @@ -484,7 +486,7 @@ static void *rif_seq_start(struct seq_file *seq, loff_t *pos) { - spin_lock_bh(&rif_lock); + spin_lock_irq(&rif_lock); return *pos ? rif_get_idx(*pos - 1) : SEQ_START_TOKEN; } @@ -515,7 +517,7 @@ static void rif_seq_stop(struct seq_file *seq, void *v) { - spin_unlock_bh(&rif_lock); + spin_unlock_irq(&rif_lock); } static int rif_seq_show(struct seq_file *seq, void *v) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/net/ax25/af_ax25.c linux-2.6.10/net/ax25/af_ax25.c --- linux.vanilla-2.6.10/net/ax25/af_ax25.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/net/ax25/af_ax25.c 2004-12-26 22:07:44.000000000 +0000 @@ -207,8 +207,16 @@ continue; if (s->ax25_dev == NULL) continue; - if (ax25cmp(&s->source_addr, src_addr) == 0 && - ax25cmp(&s->dest_addr, dest_addr) == 0) { + if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) { + if (digi != NULL && digi->ndigi != 0) { + if (s->digipeat == NULL) + continue; + if (ax25digicmp(s->digipeat, digi) != 0) + continue; + } else { + if (s->digipeat != NULL && s->digipeat->ndigi != 0) + continue; + } ax25_cb_hold(s); spin_unlock_bh(&ax25_list_lock); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/net/bridge/br_ioctl.c linux-2.6.10/net/bridge/br_ioctl.c --- linux.vanilla-2.6.10/net/bridge/br_ioctl.c 2004-12-25 21:13:49.000000000 +0000 +++ linux-2.6.10/net/bridge/br_ioctl.c 2005-01-07 15:46:41.000000000 +0000 @@ -324,6 +324,8 @@ int *indices; int ret = 0; + if (args[2] >= 16384) + return -ENOMEM; indices = kmalloc(args[2]*sizeof(int), GFP_KERNEL); if (indices == NULL) return -ENOMEM; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/net/compat.c linux-2.6.10/net/compat.c --- linux.vanilla-2.6.10/net/compat.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/net/compat.c 2005-01-06 21:52:09.572411792 +0000 @@ -125,7 +125,7 @@ (struct compat_cmsghdr __user *)NULL) #define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \ - ((ucmlen) >= sizeof(struct cmsghdr) && \ + ((ucmlen) >= sizeof(struct compat_cmsghdr) && \ (ucmlen) <= (unsigned long) \ ((mhdr)->msg_controllen - \ ((char *)(ucmsg) - (char *)(mhdr)->msg_control))) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/net/ipv6/netfilter/ip6_tables.c linux-2.6.10/net/ipv6/netfilter/ip6_tables.c --- linux.vanilla-2.6.10/net/ipv6/netfilter/ip6_tables.c 2004-12-25 21:15:46.000000000 +0000 +++ linux-2.6.10/net/ipv6/netfilter/ip6_tables.c 2005-01-07 15:45:36.000000000 +0000 @@ -1168,6 +1168,11 @@ ret = -EFAULT; goto free_newinfo; } + + if(tmp.num_counters >= (4 << 20)/sizeof(struct ip6t_counters)) { + ret = -ENOMEM; + goto free_newinfo; + } counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters)); if (!counters) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/net/rose/rose_route.c linux-2.6.10/net/rose/rose_route.c --- linux.vanilla-2.6.10/net/rose/rose_route.c 2004-12-25 21:13:48.000000000 +0000 +++ linux-2.6.10/net/rose/rose_route.c 2005-01-07 15:48:49.055797584 +0000 @@ -727,7 +727,8 @@ } if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; - + if(rose_route.ndigis > 8) /* No more than 8 digipeats */ + return -EINVAL; err = rose_add_node(&rose_route, dev); dev_put(dev); return err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/security/commoncap.c linux-2.6.10/security/commoncap.c --- linux.vanilla-2.6.10/security/commoncap.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/security/commoncap.c 2004-12-26 19:00:56.000000000 +0000 @@ -149,7 +149,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.10/security/dummy.c linux-2.6.10/security/dummy.c --- linux.vanilla-2.6.10/security/dummy.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/security/dummy.c 2004-12-26 19:01:07.000000000 +0000 @@ -181,7 +181,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.10/sound/core/control.c linux-2.6.10/sound/core/control.c --- linux.vanilla-2.6.10/sound/core/control.c 2004-12-25 21:14:46.000000000 +0000 +++ linux-2.6.10/sound/core/control.c 2005-01-06 19:29:28.000000000 +0000 @@ -635,19 +635,13 @@ return result; } -static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t __user *_control) +int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control) { - snd_ctl_elem_value_t *control; snd_kcontrol_t *kctl; snd_kcontrol_volatile_t *vd; unsigned int index_offset; int result, indirect; - - control = kmalloc(sizeof(*control), GFP_KERNEL); - if (control == NULL) - return -ENOMEM; - if (copy_from_user(control, _control, sizeof(*control))) - return -EFAULT; + down_read(&card->controls_rwsem); kctl = snd_ctl_find_id(card, &control->id); if (kctl == NULL) { @@ -668,27 +662,37 @@ } } up_read(&card->controls_rwsem); + return result; +} + +static int snd_ctl_elem_read_user(snd_card_t *card, snd_ctl_elem_value_t __user *_control) +{ + snd_ctl_elem_value_t *control; + int result; + + control = kmalloc(sizeof(*control), GFP_KERNEL); + if (control == NULL) + return -ENOMEM; + if (copy_from_user(control, _control, sizeof(*control))) { + kfree(control); + return -EFAULT; + } + result = snd_ctl_elem_read(card, control); if (result >= 0) if (copy_to_user(_control, control, sizeof(*control))) - return -EFAULT; + result = -EFAULT; kfree(control); return result; } -static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control) +int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t *control) { snd_card_t *card = file->card; - snd_ctl_elem_value_t *control; snd_kcontrol_t *kctl; snd_kcontrol_volatile_t *vd; unsigned int index_offset; int result, indirect; - control = kmalloc(sizeof(*control), GFP_KERNEL); - if (control == NULL) - return -ENOMEM; - if (copy_from_user(control, _control, sizeof(*control))) - return -EFAULT; down_read(&card->controls_rwsem); kctl = snd_ctl_find_id(card, &control->id); if (kctl == NULL) { @@ -711,16 +715,30 @@ if (result > 0) { up_read(&card->controls_rwsem); snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &control->id); - result = 0; - goto __unlocked; + return 0; } } } up_read(&card->controls_rwsem); - __unlocked: + return result; +} + +static int snd_ctl_elem_write_user(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control) +{ + snd_ctl_elem_value_t *control; + int result; + + control = kmalloc(sizeof(*control), GFP_KERNEL); + if (control == NULL) + return -ENOMEM; + if (copy_from_user(control, _control, sizeof(*control))) { + kfree(control); + return -EFAULT; + } + result = snd_ctl_elem_write(file, control); if (result >= 0) if (copy_to_user(_control, control, sizeof(*control))) - return -EFAULT; + result = -EFAULT; kfree(control); return result; } @@ -1045,9 +1063,9 @@ case SNDRV_CTL_IOCTL_ELEM_INFO: return snd_ctl_elem_info(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_READ: - return snd_ctl_elem_read(ctl->card, argp); + return snd_ctl_elem_read_user(ctl->card, argp); case SNDRV_CTL_IOCTL_ELEM_WRITE: - return snd_ctl_elem_write(ctl, argp); + return snd_ctl_elem_write_user(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_LOCK: return snd_ctl_elem_lock(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_UNLOCK: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/ioctl32/hwdep32.c linux-2.6.10/sound/core/ioctl32/hwdep32.c --- linux.vanilla-2.6.10/sound/core/ioctl32/hwdep32.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/core/ioctl32/hwdep32.c 2005-01-06 19:29:28.000000000 +0000 @@ -36,24 +36,24 @@ static inline int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { - struct sndrv_hwdep_dsp_image data; - struct sndrv_hwdep_dsp_image32 data32; - mm_segment_t oldseg; - int err; + struct sndrv_hwdep_dsp_image __user *data, *dst; + struct sndrv_hwdep_dsp_image32 __user *data32, *src; + compat_caddr_t ptr; - if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + + /* index and name */ + if (copy_in_user(data, data32, 4 + 64)) + return -EFAULT; + if (__get_user(ptr, &data32->image) || + __put_user(compat_ptr(ptr), &data->image)) return -EFAULT; - memset(&data, 0, sizeof(data)); - data.index = data32.index; - memcpy(data.name, data32.name, sizeof(data.name)); - data.image = compat_ptr(data32.image); - data.length = data32.length; - data.driver_data = data32.driver_data; - oldseg = get_fs(); - set_fs(KERNEL_DS); - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data); - set_fs(oldseg); - return err; + src = data32; + dst = data; + COPY_CVT(length); + COPY_CVT(driver_data); + return file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); } DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/ioctl32/ioctl32.c linux-2.6.10/sound/core/ioctl32/ioctl32.c --- linux.vanilla-2.6.10/sound/core/ioctl32/ioctl32.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/core/ioctl32/ioctl32.c 2005-01-06 19:29:28.000000000 +0000 @@ -27,9 +27,11 @@ #include #include #include +#include #include #include "ioctl32.h" + /* * register/unregister mappers * exported for other modules @@ -93,43 +95,28 @@ unsigned char reserved[50]; } /* don't set packed attribute here */; -#define CVT_sndrv_ctl_elem_list()\ -{\ - COPY(offset);\ - COPY(space);\ - COPY(used);\ - COPY(count);\ - CPTR(pids);\ -} - static inline int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { - struct sndrv_ctl_elem_list32 data32; - struct sndrv_ctl_elem_list data; - mm_segment_t oldseg; + struct sndrv_ctl_elem_list32 __user *data32; + struct sndrv_ctl_elem_list __user *data; + compat_caddr_t ptr; int err; - if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + + /* offset, space, used, count */ + if (copy_in_user(data, data32, 4 * sizeof(u32))) return -EFAULT; - memset(&data, 0, sizeof(data)); - data.offset = data32.offset; - data.space = data32.space; - data.used = data32.used; - data.count = data32.count; - data.pids = compat_ptr(data32.pids); - oldseg = get_fs(); - set_fs(KERNEL_DS); - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data); - set_fs(oldseg); + /* pids */ + if (__get_user(ptr, &data32->pids) || + __put_user(compat_ptr(ptr), &data->pids)) + return -EFAULT; + err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); if (err < 0) return err; /* copy the result */ - data32.offset = data.offset; - data32.space = data.space; - data32.used = data.used; - data32.count = data.count; - //data.pids = data.pids; - if (copy_to_user((void __user *)arg, &data32, sizeof(data32))) + if (copy_in_user(data32, data, 4 * sizeof(u32))) return -EFAULT; return 0; } @@ -170,54 +157,59 @@ static inline int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { - struct sndrv_ctl_elem_info data; - struct sndrv_ctl_elem_info32 data32; + struct sndrv_ctl_elem_info __user *data, *src; + struct sndrv_ctl_elem_info32 __user *data32, *dst; + unsigned int type; int err; - mm_segment_t oldseg; - if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + + /* copy id */ + if (copy_in_user(&data->id, &data32->id, sizeof(data->id))) return -EFAULT; - memset(&data, 0, sizeof(data)); - data.id = data32.id; /* we need to copy the item index. * hope this doesn't break anything.. */ - data.value.enumerated.item = data32.value.enumerated.item; - oldseg = get_fs(); - set_fs(KERNEL_DS); - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data); - set_fs(oldseg); + if (copy_in_user(&data->value.enumerated.item, + &data32->value.enumerated.item, + sizeof(data->value.enumerated.item))) + return -EFAULT; + err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); if (err < 0) return err; /* restore info to 32bit */ - data32.id = data.id; - data32.type = data.type; - data32.access = data.access; - data32.count = data.count; - data32.owner = data.owner; - switch (data.type) { + /* for COPY_CVT macro */ + src = data; + dst = data32; + /* id, type, access, count */ + if (copy_in_user(&data32->id, &data->id, sizeof(data->id)) || + copy_in_user(&data32->type, &data->type, 3 * sizeof(u32))) + return -EFAULT; + COPY_CVT(owner); + __get_user(type, &data->type); + switch (type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: case SNDRV_CTL_ELEM_TYPE_INTEGER: - data32.value.integer.min = data.value.integer.min; - data32.value.integer.max = data.value.integer.max; - data32.value.integer.step = data.value.integer.step; + COPY_CVT(value.integer.min); + COPY_CVT(value.integer.max); + COPY_CVT(value.integer.step); break; case SNDRV_CTL_ELEM_TYPE_INTEGER64: - data32.value.integer64.min = data.value.integer64.min; - data32.value.integer64.max = data.value.integer64.max; - data32.value.integer64.step = data.value.integer64.step; + if (copy_in_user(&data32->value.integer64, + &data->value.integer64, + sizeof(data->value.integer64))) + return -EFAULT; break; case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - data32.value.enumerated.items = data.value.enumerated.items; - data32.value.enumerated.item = data.value.enumerated.item; - memcpy(data32.value.enumerated.name, data.value.enumerated.name, - sizeof(data.value.enumerated.name)); + if (copy_in_user(&data32->value.enumerated, + &data->value.enumerated, + sizeof(data->value.enumerated))) + return -EFAULT; break; default: break; } - if (copy_to_user((void __user *)arg, &data32, sizeof(data32))) - return -EFAULT; return 0; } @@ -250,128 +242,172 @@ /* hmm, it's so hard to retrieve the value type from the control id.. */ -static int get_ctl_type(struct file *file, snd_ctl_elem_id_t *id) +static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id) { - snd_ctl_file_t *ctl; snd_kcontrol_t *kctl; snd_ctl_elem_info_t info; int err; - ctl = file->private_data; - - down_read(&ctl->card->controls_rwsem); - kctl = snd_ctl_find_id(ctl->card, id); + down_read(&card->controls_rwsem); + kctl = snd_ctl_find_id(card, id); if (! kctl) { - up_read(&ctl->card->controls_rwsem); + up_read(&card->controls_rwsem); return -ENXIO; } info.id = *id; err = kctl->info(kctl, &info); - up_read(&ctl->card->controls_rwsem); + up_read(&card->controls_rwsem); if (err >= 0) err = info.type; return err; } +extern int snd_major; static inline int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { struct sndrv_ctl_elem_value *data; - struct sndrv_ctl_elem_value32 *data32; + struct sndrv_ctl_elem_value32 __user *data32; + snd_ctl_file_t *ctl; int err, i; int type; - mm_segment_t oldseg; - /* FIXME: check the sane ioctl.. */ + /* sanity check */ + if (imajor(file->f_dentry->d_inode) != snd_major || + SNDRV_MINOR_DEVICE(iminor(file->f_dentry->d_inode)) != SNDRV_MINOR_CONTROL) + return -ENOTTY; + + if ((ctl = file->private_data) == NULL) + return -ENOTTY; + data32 = compat_ptr(arg); data = kmalloc(sizeof(*data), GFP_KERNEL); - data32 = kmalloc(sizeof(*data32), GFP_KERNEL); - if (data == NULL || data32 == NULL) { - err = -ENOMEM; + if (data == NULL) + return -ENOMEM; + + if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) { + err = -EFAULT; goto __end; } - - if (copy_from_user(data32, (void __user *)arg, sizeof(*data32))) { + if (__get_user(data->indirect, &data32->indirect)) { err = -EFAULT; goto __end; } - memset(data, 0, sizeof(*data)); - data->id = data32->id; - data->indirect = data32->indirect; - if (data->indirect) /* FIXME: this is not correct for long arrays */ - data->value.integer.value_ptr = compat_ptr(data32->value.integer.value_ptr); - type = get_ctl_type(file, &data->id); + /* FIXME: indirect access is not supported */ + if (data->indirect) { + err = -EINVAL; + goto __end; + } + type = get_ctl_type(ctl->card, &data->id); if (type < 0) { err = type; goto __end; } - if (! data->indirect) { - switch (type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - for (i = 0; i < 128; i++) - data->value.integer.value[i] = data32->value.integer.value[i]; - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - for (i = 0; i < 64; i++) - data->value.integer64.value[i] = data32->value.integer64.value[i]; - break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - for (i = 0; i < 128; i++) - data->value.enumerated.item[i] = data32->value.enumerated.item[i]; - break; - case SNDRV_CTL_ELEM_TYPE_BYTES: - memcpy(data->value.bytes.data, data32->value.bytes.data, - sizeof(data->value.bytes.data)); - break; - case SNDRV_CTL_ELEM_TYPE_IEC958: - data->value.iec958 = data32->value.iec958; - break; - default: - printk("unknown type %d\n", type); - break; + + switch (type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + for (i = 0; i < 128; i++) { + int val; + if (__get_user(val, &data32->value.integer.value[i])) { + err = -EFAULT; + goto __end; + } + data->value.integer.value[i] = val; } + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + if (__copy_from_user(data->value.integer64.value, + data32->value.integer64.value, + sizeof(data->value.integer64.value))) { + err = -EFAULT; + goto __end; + } + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + if (__copy_from_user(data->value.enumerated.item, + data32->value.enumerated.item, + sizeof(data32->value.enumerated.item))) { + err = -EFAULT; + goto __end; + } + break; + case SNDRV_CTL_ELEM_TYPE_BYTES: + if (__copy_from_user(data->value.bytes.data, + data32->value.bytes.data, + sizeof(data32->value.bytes.data))) { + err = -EFAULT; + goto __end; + } + break; + case SNDRV_CTL_ELEM_TYPE_IEC958: + if (__copy_from_user(&data->value.iec958, + &data32->value.iec958, + sizeof(data32->value.iec958))) { + err = -EFAULT; + goto __end; + } + break; + default: + printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); + err = -EINVAL; + goto __end; } - oldseg = get_fs(); - set_fs(KERNEL_DS); - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); - set_fs(oldseg); + if (native_ctl == SNDRV_CTL_IOCTL_ELEM_READ) + err = snd_ctl_elem_read(ctl->card, data); + else + err = snd_ctl_elem_write(ctl, data); if (err < 0) goto __end; /* restore info to 32bit */ - if (! data->indirect) { - switch (type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - for (i = 0; i < 128; i++) - data32->value.integer.value[i] = data->value.integer.value[i]; - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - for (i = 0; i < 64; i++) - data32->value.integer64.value[i] = data->value.integer64.value[i]; - break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - for (i = 0; i < 128; i++) - data32->value.enumerated.item[i] = data->value.enumerated.item[i]; - break; - case SNDRV_CTL_ELEM_TYPE_BYTES: - memcpy(data32->value.bytes.data, data->value.bytes.data, - sizeof(data->value.bytes.data)); - break; - case SNDRV_CTL_ELEM_TYPE_IEC958: - data32->value.iec958 = data->value.iec958; - break; - default: - break; + switch (type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + for (i = 0; i < 128; i++) { + int val; + val = data->value.integer.value[i]; + if (__put_user(val, &data32->value.integer.value[i])) { + err = -EFAULT; + goto __end; + } + } + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + if (__copy_to_user(data32->value.integer64.value, + data->value.integer64.value, + sizeof(data32->value.integer64.value))) { + err = -EFAULT; + goto __end; + } + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + if (__copy_to_user(data32->value.enumerated.item, + data->value.enumerated.item, + sizeof(data32->value.enumerated.item))) { + err = -EFAULT; + goto __end; } + break; + case SNDRV_CTL_ELEM_TYPE_BYTES: + if (__copy_to_user(data32->value.bytes.data, + data->value.bytes.data, + sizeof(data32->value.bytes.data))) { + err = -EFAULT; + goto __end; + } + break; + case SNDRV_CTL_ELEM_TYPE_IEC958: + if (__copy_to_user(&data32->value.iec958, + &data->value.iec958, + sizeof(data32->value.iec958))) { + err = -EFAULT; + goto __end; + } + break; } err = 0; - if (copy_to_user((void __user *)arg, data32, sizeof(*data32))) - err = -EFAULT; __end: - if (data32) - kfree(data32); if (data) kfree(data); return err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/ioctl32/ioctl32.h linux-2.6.10/sound/core/ioctl32/ioctl32.h --- linux.vanilla-2.6.10/sound/core/ioctl32/ioctl32.h 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/core/ioctl32/ioctl32.h 2005-01-06 19:29:28.000000000 +0000 @@ -28,20 +28,37 @@ #include -#define COPY(x) (dst->x = src->x) -#define CPTR(x) (dst->x = compat_ptr(src->x)) +#define COPY(x) \ + do { \ + if (copy_in_user(&dst->x, &src->x, sizeof(dst->x))) \ + return -EFAULT; \ + } while (0) + +#define COPY_ARRAY(x) \ + do { \ + if (copy_in_user(dst->x, src->x, sizeof(dst->x))) \ + return -EFAULT; \ + } while (0) + +#define COPY_CVT(x) \ + do { \ + __typeof__(src->x) __val_tmp; \ + if (get_user(__val_tmp, &src->x) || \ + put_user(__val_tmp, &dst->x))\ + return -EFAULT; \ + } while (0) #define convert_from_32(type, dstp, srcp)\ {\ - struct sndrv_##type *dst = dstp;\ - struct sndrv_##type##32 *src = srcp;\ + struct sndrv_##type __user *dst = dstp;\ + struct sndrv_##type##32 __user *src = srcp;\ CVT_##sndrv_##type();\ } #define convert_to_32(type, dstp, srcp)\ {\ - struct sndrv_##type *src = srcp;\ - struct sndrv_##type##32 *dst = dstp;\ + struct sndrv_##type __user *src = srcp;\ + struct sndrv_##type##32 __user *dst = dstp;\ CVT_##sndrv_##type();\ } @@ -49,65 +66,19 @@ #define DEFINE_ALSA_IOCTL(type) \ static inline int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\ {\ - struct sndrv_##type##32 data32;\ - struct sndrv_##type data;\ - mm_segment_t oldseg;\ + struct sndrv_##type##32 __user *data32;\ + struct sndrv_##type __user *data;\ int err;\ - if (copy_from_user(&data32, (void __user *)arg, sizeof(data32)))\ - return -EFAULT;\ - memset(&data, 0, sizeof(data));\ - convert_from_32(type, &data, &data32);\ - oldseg = get_fs();\ - set_fs(KERNEL_DS);\ - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);\ - set_fs(oldseg);\ - if (err < 0) \ - return err;\ - if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\ - convert_to_32(type, &data32, &data);\ - if (copy_to_user((void __user *)arg, &data32, sizeof(data32)))\ - return -EFAULT;\ - }\ - return 0;\ -} - -#define DEFINE_ALSA_IOCTL_BIG(type) \ -static inline int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\ -{\ - struct sndrv_##type##32 *data32;\ - struct sndrv_##type *data;\ - mm_segment_t oldseg;\ - int err;\ - data32 = kmalloc(sizeof(*data32), GFP_KERNEL); \ - data = kmalloc(sizeof(*data), GFP_KERNEL); \ - if (data32 == NULL || data == NULL) { \ - err = -ENOMEM; \ - goto __end; \ - }\ - if (copy_from_user(data32, (void __user *)arg, sizeof(*data32))) { \ - err = -EFAULT; \ - goto __end; \ - }\ - memset(data, 0, sizeof(*data));\ + data32 = compat_ptr(arg);\ + data = compat_alloc_user_space(sizeof(*data));\ convert_from_32(type, data, data32);\ - oldseg = get_fs();\ - set_fs(KERNEL_DS);\ err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);\ - set_fs(oldseg);\ if (err < 0) \ - goto __end;\ - err = 0;\ + return err;\ if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\ convert_to_32(type, data32, data);\ - if (copy_to_user((void __user *)arg, data32, sizeof(*data32)))\ - err = -EFAULT;\ }\ - __end:\ - if (data)\ - kfree(data);\ - if (data32)\ - kfree(data32);\ - return err;\ + return 0;\ } #define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/ioctl32/pcm32.c linux-2.6.10/sound/core/ioctl32/pcm32.c --- linux.vanilla-2.6.10/sound/core/ioctl32/pcm32.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/core/ioctl32/pcm32.c 2005-01-06 19:29:28.000000000 +0000 @@ -24,6 +24,7 @@ #include #include #include +#include #include "ioctl32.h" @@ -41,23 +42,15 @@ u32 val; }; -#define CVT_sndrv_pcm_sframes_str() { COPY(val); } -#define CVT_sndrv_pcm_uframes_str() { COPY(val); } +#define CVT_sndrv_pcm_sframes_str() { COPY_CVT(val); } +#define CVT_sndrv_pcm_uframes_str() { COPY_CVT(val); } -struct sndrv_interval32 { - u32 min, max; - unsigned int openmin:1, - openmax:1, - integer:1, - empty:1; -}; - struct sndrv_pcm_hw_params32 { u32 flags; struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */ struct sndrv_mask mres[5]; /* reserved masks */ - struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; struct sndrv_interval ires[9]; /* reserved intervals */ u32 rmask; u32 cmask; @@ -69,31 +62,6 @@ unsigned char reserved[64]; } __attribute__((packed)); -#define numberof(array) ARRAY_SIZE(array) - -#define CVT_sndrv_pcm_hw_params()\ -{\ - unsigned int i;\ - COPY(flags);\ - for (i = 0; i < numberof(dst->masks); i++)\ - COPY(masks[i]);\ - for (i = 0; i < numberof(dst->intervals); i++) {\ - COPY(intervals[i].min);\ - COPY(intervals[i].max);\ - COPY(intervals[i].openmin);\ - COPY(intervals[i].openmax);\ - COPY(intervals[i].integer);\ - COPY(intervals[i].empty);\ - }\ - COPY(rmask);\ - COPY(cmask);\ - COPY(info);\ - COPY(msbits);\ - COPY(rate_num);\ - COPY(rate_den);\ - COPY(fifo_size);\ -} - struct sndrv_pcm_sw_params32 { s32 tstamp_mode; u32 period_step; @@ -113,13 +81,13 @@ COPY(tstamp_mode);\ COPY(period_step);\ COPY(sleep_min);\ - COPY(avail_min);\ - COPY(xfer_align);\ - COPY(start_threshold);\ - COPY(stop_threshold);\ - COPY(silence_threshold);\ - COPY(silence_size);\ - COPY(boundary);\ + COPY_CVT(avail_min);\ + COPY_CVT(xfer_align);\ + COPY_CVT(start_threshold);\ + COPY_CVT(stop_threshold);\ + COPY_CVT(silence_threshold);\ + COPY_CVT(silence_size);\ + COPY_CVT(boundary);\ } struct sndrv_pcm_channel_info32 { @@ -132,7 +100,7 @@ #define CVT_sndrv_pcm_channel_info()\ {\ COPY(channel);\ - COPY(offset);\ + COPY_CVT(offset);\ COPY(first);\ COPY(step);\ } @@ -154,16 +122,16 @@ #define CVT_sndrv_pcm_status()\ {\ COPY(state);\ - COPY(trigger_tstamp.tv_sec);\ - COPY(trigger_tstamp.tv_nsec);\ - COPY(tstamp.tv_sec);\ - COPY(tstamp.tv_nsec);\ - COPY(appl_ptr);\ - COPY(hw_ptr);\ - COPY(delay);\ - COPY(avail);\ - COPY(avail_max);\ - COPY(overrange);\ + COPY_CVT(trigger_tstamp.tv_sec);\ + COPY_CVT(trigger_tstamp.tv_nsec);\ + COPY_CVT(tstamp.tv_sec);\ + COPY_CVT(tstamp.tv_nsec);\ + COPY_CVT(appl_ptr);\ + COPY_CVT(hw_ptr);\ + COPY_CVT(delay);\ + COPY_CVT(avail);\ + COPY_CVT(avail_max);\ + COPY_CVT(overrange);\ COPY(suspended_state);\ } @@ -173,61 +141,73 @@ DEFINE_ALSA_IOCTL(pcm_channel_info); DEFINE_ALSA_IOCTL(pcm_status); -/* recalcuate the boundary within 32bit */ -static void recalculate_boundary(struct file *file) +/* sanity device check */ +extern int snd_major; +static int sanity_check_pcm(struct file *file) { - snd_pcm_file_t *pcm_file; - snd_pcm_substream_t *substream; - snd_pcm_runtime_t *runtime; + unsigned short minor; + if (imajor(file->f_dentry->d_inode) != snd_major) + return -ENOTTY; + minor = iminor(file->f_dentry->d_inode); + if (minor >= 256 || + minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK) + return -ENOTTY; + return 0; +} - /* FIXME: need to check whether fop->ioctl is sane */ - if (! (pcm_file = file->private_data)) - return; - if (! (substream = pcm_file->substream)) - return; - if (! (runtime = substream->runtime)) +/* recalcuate the boundary within 32bit */ +static void recalculate_boundary(snd_pcm_runtime_t *runtime) +{ + if (! runtime->buffer_size) return; runtime->boundary = runtime->buffer_size; while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) runtime->boundary *= 2; } -static inline int _snd_ioctl32_pcm_hw_params(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) +/* both for HW_PARAMS and HW_REFINE */ +static int _snd_ioctl32_pcm_hw_params(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { - struct sndrv_pcm_hw_params32 *data32; + struct sndrv_pcm_hw_params32 __user *data32; struct sndrv_pcm_hw_params *data; - mm_segment_t oldseg; + snd_pcm_file_t *pcm_file; + snd_pcm_substream_t *substream; + snd_pcm_runtime_t *runtime; int err; - data32 = kmalloc(sizeof(*data32), GFP_KERNEL); + if (sanity_check_pcm(file)) + return -ENOTTY; + if (! (pcm_file = file->private_data)) + return -ENOTTY; + if (! (substream = pcm_file->substream)) + return -ENOTTY; + if (! (runtime = substream->runtime)) + return -ENOTTY; + + data32 = compat_ptr(arg); data = kmalloc(sizeof(*data), GFP_KERNEL); - if (data32 == NULL || data == NULL) { - err = -ENOMEM; - goto __end; - } - if (copy_from_user(data32, (void __user *)arg, sizeof(*data32))) { + if (data == NULL) + return -ENOMEM; + if (copy_from_user(data, data32, sizeof(*data32))) { err = -EFAULT; - goto __end; + goto error; } - memset(data, 0, sizeof(*data)); - convert_from_32(pcm_hw_params, data, data32); - oldseg = get_fs(); - set_fs(KERNEL_DS); - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); - set_fs(oldseg); + if (native_ctl == SNDRV_PCM_IOCTL_HW_REFINE) + err = snd_pcm_hw_refine(substream, data); + else + err = snd_pcm_hw_params(substream, data); if (err < 0) - goto __end; - err = 0; - convert_to_32(pcm_hw_params, data32, data); - if (copy_to_user((void __user *)arg, data32, sizeof(*data32))) + goto error; + if (copy_to_user(data32, data, sizeof(*data32)) || + __put_user((u32)data->fifo_size, &data32->fifo_size)) { err = -EFAULT; - else - recalculate_boundary(file); - __end: - if (data) - kfree(data); - if (data32) - kfree(data32); + goto error; + } + + if (native_ctl == SNDRV_PCM_IOCTL_HW_PARAMS) + recalculate_boundary(runtime); + error: + kfree(data); return err; } @@ -240,27 +220,27 @@ u32 frames; } __attribute__((packed)); -static inline int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) +static int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { struct sndrv_xferi32 data32; - struct sndrv_xferi data; - mm_segment_t oldseg; + struct sndrv_xferi __user *data; + snd_pcm_sframes_t result; int err; if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) return -EFAULT; - memset(&data, 0, sizeof(data)); - data.result = data32.result; - data.buf = compat_ptr(data32.buf); - data.frames = data32.frames; - oldseg = get_fs(); - set_fs(KERNEL_DS); - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data); - set_fs(oldseg); + data = compat_alloc_user_space(sizeof(*data)); + if (put_user((snd_pcm_sframes_t)data32.result, &data->result) || + __put_user(compat_ptr(data32.buf), &data->buf) || + __put_user((snd_pcm_uframes_t)data32.frames, &data->frames)) + return -EFAULT; + err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); if (err < 0) return err; /* copy the result */ - data32.result = data.result; + if (__get_user(result, &data->result)) + return -EFAULT; + data32.result = result; if (copy_to_user((void __user *)arg, &data32, sizeof(data32))) return -EFAULT; return 0; @@ -280,22 +260,24 @@ * handler there expands again the same 128 pointers on stack, so it is better * to handle the function (calling pcm_readv/writev) directly in this handler. */ -static inline int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) +static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { snd_pcm_file_t *pcm_file; snd_pcm_substream_t *substream; + struct sndrv_xfern32 __user *srcptr = compat_ptr(arg); struct sndrv_xfern32 data32; - struct sndrv_xfern32 __user *srcptr = (void __user *)arg; - void __user **bufs = NULL; + void __user **bufs; int err = 0, ch, i; u32 __user *bufptr; - mm_segment_t oldseg; - - /* FIXME: need to check whether fop->ioctl is sane */ - pcm_file = file->private_data; - substream = pcm_file->substream; - snd_assert(substream != NULL && substream->runtime, return -ENXIO); + if (sanity_check_pcm(file)) + return -ENOTTY; + if (! (pcm_file = file->private_data)) + return -ENOTTY; + if (! (substream = pcm_file->substream)) + return -ENOTTY; + if (! substream->runtime) + return -ENOTTY; /* check validty of the command */ switch (native_ctl) { @@ -312,22 +294,21 @@ } if ((ch = substream->runtime->channels) > 128) return -EINVAL; - if (get_user(data32.frames, &srcptr->frames)) + if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) return -EFAULT; - __get_user(data32.bufs, &srcptr->bufs); bufptr = compat_ptr(data32.bufs); - bufs = kmalloc(sizeof(void *) * 128, GFP_KERNEL); + bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL); if (bufs == NULL) return -ENOMEM; for (i = 0; i < ch; i++) { u32 ptr; - if (get_user(ptr, bufptr)) + if (get_user(ptr, bufptr)) { + kfree(bufs); return -EFAULT; + } bufs[ch] = compat_ptr(ptr); bufptr++; } - oldseg = get_fs(); - set_fs(KERNEL_DS); switch (native_ctl) { case SNDRV_PCM_IOCTL_WRITEN_FRAMES: err = snd_pcm_lib_writev(substream, bufs, data32.frames); @@ -336,109 +317,15 @@ err = snd_pcm_lib_readv(substream, bufs, data32.frames); break; } - set_fs(oldseg); if (err >= 0) { if (put_user(err, &srcptr->result)) err = -EFAULT; } kfree(bufs); - return 0; -} - - -struct sndrv_pcm_hw_params_old32 { - u32 flags; - u32 masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - - SNDRV_PCM_HW_PARAM_ACCESS + 1]; - struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_TICK_TIME - - SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1]; - u32 rmask; - u32 cmask; - u32 info; - u32 msbits; - u32 rate_num; - u32 rate_den; - u32 fifo_size; - unsigned char reserved[64]; -} __attribute__((packed)); - -#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5)) -#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5)) - -static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, struct sndrv_pcm_hw_params_old32 *oparams) -{ - unsigned int i; - - memset(params, 0, sizeof(*params)); - params->flags = oparams->flags; - for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) - params->masks[i].bits[0] = oparams->masks[i]; - memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals)); - params->rmask = __OLD_TO_NEW_MASK(oparams->rmask); - params->cmask = __OLD_TO_NEW_MASK(oparams->cmask); - params->info = oparams->info; - params->msbits = oparams->msbits; - params->rate_num = oparams->rate_num; - params->rate_den = oparams->rate_den; - params->fifo_size = oparams->fifo_size; -} - -static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old32 *oparams, snd_pcm_hw_params_t *params) -{ - unsigned int i; - - memset(oparams, 0, sizeof(*oparams)); - oparams->flags = params->flags; - for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) - oparams->masks[i] = params->masks[i].bits[0]; - memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals)); - oparams->rmask = __NEW_TO_OLD_MASK(params->rmask); - oparams->cmask = __NEW_TO_OLD_MASK(params->cmask); - oparams->info = params->info; - oparams->msbits = params->msbits; - oparams->rate_num = params->rate_num; - oparams->rate_den = params->rate_den; - oparams->fifo_size = params->fifo_size; -} - -static inline int _snd_ioctl32_pcm_hw_params_old(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) -{ - struct sndrv_pcm_hw_params_old32 *data32; - struct sndrv_pcm_hw_params *data; - mm_segment_t oldseg; - int err; - - data32 = kcalloc(1, sizeof(*data32), GFP_KERNEL); - data = kcalloc(1, sizeof(*data), GFP_KERNEL); - if (data32 == NULL || data == NULL) { - err = -ENOMEM; - goto __end; - } - if (copy_from_user(data32, (void __user *)arg, sizeof(*data32))) { - err = -EFAULT; - goto __end; - } - snd_pcm_hw_convert_from_old_params(data, data32); - oldseg = get_fs(); - set_fs(KERNEL_DS); - err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data); - set_fs(oldseg); - if (err < 0) - goto __end; - snd_pcm_hw_convert_to_old_params(data32, data); - err = 0; - if (copy_to_user((void __user *)arg, data32, sizeof(*data32))) - err = -EFAULT; - else - recalculate_boundary(file); - __end: - if (data) - kfree(data); - if (data32) - kfree(data32); return err; } + struct sndrv_pcm_mmap_status32 { s32 state; s32 pad1; @@ -469,15 +356,15 @@ COPY(flags);\ COPY(s.status.state);\ COPY(s.status.pad1);\ - COPY(s.status.hw_ptr);\ - COPY(s.status.tstamp.tv_sec);\ - COPY(s.status.tstamp.tv_nsec);\ + COPY_CVT(s.status.hw_ptr);\ + COPY_CVT(s.status.tstamp.tv_sec);\ + COPY_CVT(s.status.tstamp.tv_nsec);\ COPY(s.status.suspended_state);\ - COPY(c.control.appl_ptr);\ - COPY(c.control.avail_min);\ + COPY_CVT(c.control.appl_ptr);\ + COPY_CVT(c.control.avail_min);\ } -DEFINE_ALSA_IOCTL_BIG(pcm_sync_ptr); +DEFINE_ALSA_IOCTL(pcm_sync_ptr); /* */ @@ -485,8 +372,6 @@ DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine, pcm_hw_params, SNDRV_PCM_IOCTL_HW_REFINE); DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params, pcm_hw_params, SNDRV_PCM_IOCTL_HW_PARAMS); DEFINE_ALSA_IOCTL_ENTRY(pcm_sw_params, pcm_sw_params, SNDRV_PCM_IOCTL_SW_PARAMS); -DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine_old, pcm_hw_params_old, SNDRV_PCM_IOCTL_HW_REFINE); -DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params_old, pcm_hw_params_old, SNDRV_PCM_IOCTL_HW_PARAMS); DEFINE_ALSA_IOCTL_ENTRY(pcm_status, pcm_status, SNDRV_PCM_IOCTL_STATUS); DEFINE_ALSA_IOCTL_ENTRY(pcm_delay, pcm_sframes_str, SNDRV_PCM_IOCTL_DELAY); DEFINE_ALSA_IOCTL_ENTRY(pcm_channel_info, pcm_channel_info, SNDRV_PCM_IOCTL_CHANNEL_INFO); @@ -538,8 +423,6 @@ SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32), SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32), SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32), - SNDRV_PCM_IOCTL_HW_REFINE_OLD32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old32), - SNDRV_PCM_IOCTL_HW_PARAMS_OLD32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old32), SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32), }; @@ -551,8 +434,6 @@ MAP_COMPAT(SNDRV_PCM_IOCTL_TSTAMP), { SNDRV_PCM_IOCTL_HW_REFINE32, AP(pcm_hw_refine) }, { SNDRV_PCM_IOCTL_HW_PARAMS32, AP(pcm_hw_params) }, - { SNDRV_PCM_IOCTL_HW_REFINE_OLD32, AP(pcm_hw_refine_old) }, - { SNDRV_PCM_IOCTL_HW_PARAMS_OLD32, AP(pcm_hw_params_old) }, MAP_COMPAT(SNDRV_PCM_IOCTL_HW_FREE), { SNDRV_PCM_IOCTL_SW_PARAMS32, AP(pcm_sw_params) }, { SNDRV_PCM_IOCTL_STATUS32, AP(pcm_status) }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/ioctl32/rawmidi32.c linux-2.6.10/sound/core/ioctl32/rawmidi32.c --- linux.vanilla-2.6.10/sound/core/ioctl32/rawmidi32.c 2004-12-25 21:14:45.000000000 +0000 +++ linux-2.6.10/sound/core/ioctl32/rawmidi32.c 2005-01-06 19:29:28.000000000 +0000 @@ -38,9 +38,11 @@ #define CVT_sndrv_rawmidi_params()\ {\ COPY(stream);\ - COPY(buffer_size);\ - COPY(avail_min);\ - COPY(no_active_sensing);\ + COPY_CVT(buffer_size);\ + COPY_CVT(avail_min);\ + if (copy_in_user(((size_t __user *)&dst->avail_min + 1),\ + ((size_t __user *)&src->avail_min + 1), 4)) \ + return -EFAULT;\ } struct sndrv_rawmidi_status32 { @@ -54,10 +56,10 @@ #define CVT_sndrv_rawmidi_status()\ {\ COPY(stream);\ - COPY(tstamp.tv_sec);\ - COPY(tstamp.tv_nsec);\ - COPY(avail);\ - COPY(xruns);\ + COPY_CVT(tstamp.tv_sec);\ + COPY_CVT(tstamp.tv_nsec);\ + COPY_CVT(avail);\ + COPY_CVT(xruns);\ } DEFINE_ALSA_IOCTL(rawmidi_params); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/ioctl32/seq32.c linux-2.6.10/sound/core/ioctl32/seq32.c --- linux.vanilla-2.6.10/sound/core/ioctl32/seq32.c 2004-12-25 21:14:45.000000000 +0000 +++ linux-2.6.10/sound/core/ioctl32/seq32.c 2005-01-06 19:29:28.000000000 +0000 @@ -42,13 +42,14 @@ u32 kernel; /* reserved for kernel use (must be NULL) */ u32 flags; /* misc. conditioning */ - char reserved[60]; /* for future use */ + unsigned char time_queue; /* queue # for timestamping */ + char reserved[59]; /* for future use */ }; #define CVT_sndrv_seq_port_info()\ {\ COPY(addr);\ - memcpy(dst->name, src->name, sizeof(dst->name));\ + COPY_ARRAY(name);\ COPY(capability);\ COPY(type);\ COPY(midi_channels);\ @@ -57,6 +58,7 @@ COPY(read_use);\ COPY(write_use);\ COPY(flags);\ + COPY(time_queue);\ } DEFINE_ALSA_IOCTL(seq_port_info); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/ioctl32/timer32.c linux-2.6.10/sound/core/ioctl32/timer32.c --- linux.vanilla-2.6.10/sound/core/ioctl32/timer32.c 2004-12-25 21:14:45.000000000 +0000 +++ linux-2.6.10/sound/core/ioctl32/timer32.c 2005-01-06 19:29:28.000000000 +0000 @@ -41,9 +41,9 @@ {\ COPY(flags);\ COPY(card);\ - memcpy(dst->id, src->id, sizeof(src->id));\ - memcpy(dst->name, src->name, sizeof(src->name));\ - COPY(resolution);\ + COPY_ARRAY(id);\ + COPY_ARRAY(name);\ + COPY_CVT(resolution);\ } struct sndrv_timer_status32 { @@ -57,8 +57,8 @@ #define CVT_sndrv_timer_status()\ {\ - COPY(tstamp.tv_sec);\ - COPY(tstamp.tv_nsec);\ + COPY_CVT(tstamp.tv_sec);\ + COPY_CVT(tstamp.tv_nsec);\ COPY(resolution);\ COPY(lost);\ COPY(overrun);\ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/memory.c linux-2.6.10/sound/core/memory.c --- linux.vanilla-2.6.10/sound/core/memory.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/core/memory.c 2005-01-06 19:29:28.000000000 +0000 @@ -257,7 +257,7 @@ * * Returns zero if successful, or non-zero on failure. */ -int copy_to_user_fromio(void __user *dst, const void __iomem *src, size_t count) +int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count) { #if defined(__i386__) || defined(CONFIG_SPARC32) return copy_to_user(dst, (const void*)src, count) ? -EFAULT : 0; @@ -288,7 +288,7 @@ * * Returns zero if successful, or non-zero on failure. */ -int copy_from_user_toio(void __iomem *dst, const void __user *src, size_t count) +int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count) { #if defined(__i386__) || defined(CONFIG_SPARC32) return copy_from_user((void*)dst, src, count) ? -EFAULT : 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/pcm_lib.c linux-2.6.10/sound/core/pcm_lib.c --- linux.vanilla-2.6.10/sound/core/pcm_lib.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/core/pcm_lib.c 2005-01-06 19:29:28.000000000 +0000 @@ -2660,6 +2660,7 @@ EXPORT_SYMBOL(snd_pcm_hw_param_near); EXPORT_SYMBOL(snd_pcm_hw_param_set); EXPORT_SYMBOL(snd_pcm_hw_refine); +EXPORT_SYMBOL(snd_pcm_hw_params); EXPORT_SYMBOL(snd_pcm_hw_constraints_init); EXPORT_SYMBOL(snd_pcm_hw_constraints_complete); EXPORT_SYMBOL(snd_pcm_hw_constraint_list); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/pcm_native.c linux-2.6.10/sound/core/pcm_native.c --- linux.vanilla-2.6.10/sound/core/pcm_native.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/core/pcm_native.c 2005-01-06 19:29:28.000000000 +0000 @@ -329,8 +329,8 @@ return err; } -static int snd_pcm_hw_params(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params) +int snd_pcm_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *params) { snd_pcm_runtime_t *runtime; int err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/core/sound.c linux-2.6.10/sound/core/sound.c --- linux.vanilla-2.6.10/sound/core/sound.c 2004-12-25 21:14:45.000000000 +0000 +++ linux-2.6.10/sound/core/sound.c 2005-01-06 19:29:28.000000000 +0000 @@ -476,6 +476,10 @@ EXPORT_SYMBOL(snd_ctl_notify); EXPORT_SYMBOL(snd_ctl_register_ioctl); EXPORT_SYMBOL(snd_ctl_unregister_ioctl); +#ifdef CONFIG_COMPAT +EXPORT_SYMBOL(snd_ctl_elem_read); +EXPORT_SYMBOL(snd_ctl_elem_write); +#endif /* misc.c */ EXPORT_SYMBOL(snd_task_name); #ifdef CONFIG_SND_VERBOSE_PRINTK diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/drivers/opl3/Makefile linux-2.6.10/sound/drivers/opl3/Makefile --- linux.vanilla-2.6.10/sound/drivers/opl3/Makefile 2004-12-25 21:14:48.000000000 +0000 +++ linux-2.6.10/sound/drivers/opl3/Makefile 2005-01-06 19:29:28.000000000 +0000 @@ -18,4 +18,5 @@ sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o +obj-$(CONFIG_SND_OPL4_LIB) += snd-opl3-lib.o obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/drivers/vx/vx_core.c linux-2.6.10/sound/drivers/vx/vx_core.c --- linux.vanilla-2.6.10/sound/drivers/vx/vx_core.c 2004-12-25 21:14:48.000000000 +0000 +++ linux-2.6.10/sound/drivers/vx/vx_core.c 2005-01-06 19:29:28.000000000 +0000 @@ -734,7 +734,7 @@ snd_assert(card && hw && ops, return NULL); - chip = kcalloc(1, sizeof(chip) + extra_size, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip) + extra_size, GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "vx_core: no memory\n"); return NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/isa/opl3sa2.c linux-2.6.10/sound/isa/opl3sa2.c --- linux.vanilla-2.6.10/sound/isa/opl3sa2.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/isa/opl3sa2.c 2005-01-06 22:27:31.000000000 +0000 @@ -713,7 +713,7 @@ chip->single_dma = 1; if ((err = snd_opl3sa2_detect(chip)) < 0) goto __error; - if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2/3", (void *)chip)) { + if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", (void *)chip)) { snd_printk(KERN_ERR "opl3sa2: can't grab IRQ %d\n", xirq); err = -ENODEV; goto __error; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/ac97/ac97_patch.c linux-2.6.10/sound/pci/ac97/ac97_patch.c --- linux.vanilla-2.6.10/sound/pci/ac97/ac97_patch.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/ac97/ac97_patch.c 2005-01-06 19:29:28.000000000 +0000 @@ -1013,8 +1013,20 @@ return patch_build_controls(ac97, &snd_ac97_ad198x_spdif_source, 1); } +static const snd_kcontrol_new_t snd_ac97_ad1981x_jack_sense[] = { + AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 11, 1, 0), + AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0), +}; + +static int patch_ad1981a_specific(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_ad1981x_jack_sense, + ARRAY_SIZE(snd_ac97_ad1981x_jack_sense)); +} + static struct snd_ac97_build_ops patch_ad1981a_build_ops = { - .build_post_spdif = patch_ad198x_post_spdif + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1981a_specific }; int patch_ad1981a(ac97_t *ac97) @@ -1023,6 +1035,7 @@ ac97->build_ops = &patch_ad1981a_build_ops; snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); ac97->flags |= AC97_STEREO_MUTES; + snd_ac97_update_bits(ac97, AC97_AD_JACK_SPDIF, 1<<11, 1<<11); /* HP jack sense */ return 0; } @@ -1031,7 +1044,12 @@ static int patch_ad1981b_specific(ac97_t *ac97) { - return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); + int err; + + if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + return err; + return patch_build_controls(ac97, snd_ac97_ad1981x_jack_sense, + ARRAY_SIZE(snd_ac97_ad1981x_jack_sense)); } static struct snd_ac97_build_ops patch_ad1981b_build_ops = { @@ -1045,6 +1063,7 @@ ac97->build_ops = &patch_ad1981b_build_ops; snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); ac97->flags |= AC97_STEREO_MUTES; + snd_ac97_update_bits(ac97, AC97_AD_JACK_SPDIF, 1<<11, 1<<11); /* HP jack sense */ return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/au88x0/au88x0_core.c linux-2.6.10/sound/pci/au88x0/au88x0_core.c --- linux.vanilla-2.6.10/sound/pci/au88x0/au88x0_core.c 2004-12-25 21:14:49.000000000 +0000 +++ linux-2.6.10/sound/pci/au88x0/au88x0_core.c 2005-01-06 19:29:28.000000000 +0000 @@ -2081,7 +2081,6 @@ || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2))) return -EBUSY; - spin_lock(&vortex->lock); if (dma >= 0) { en = 0; vortex_adb_checkinout(vortex, @@ -2277,7 +2276,6 @@ } } vortex->dma_adb[dma].nr_ch = nr_ch; - spin_unlock(&vortex->lock); #if 0 /* AC97 Codec channel setup. FIXME: this has no effect on some cards !! */ @@ -2406,22 +2404,28 @@ } if (source & IRQ_PCMOUT) { /* ALSA period acknowledge. */ + spin_lock(&vortex->lock); for (i = 0; i < NR_ADB; i++) { if (vortex->dma_adb[i].fifo_status == FIFO_START) { if (vortex_adbdma_bufshift(vortex, i)) ; + spin_unlock(&vortex->lock); snd_pcm_period_elapsed(vortex->dma_adb[i]. substream); + spin_lock(&vortex->lock); } } #ifndef CHIP_AU8810 for (i = 0; i < NR_WT; i++) { if (vortex->dma_wt[i].fifo_status == FIFO_START) { if (vortex_wtdma_bufshift(vortex, i)) ; + spin_unlock(&vortex->lock); snd_pcm_period_elapsed(vortex->dma_wt[i]. substream); + spin_lock(&vortex->lock); } } #endif + spin_unlock(&vortex->lock); handled = 1; } //Acknowledge the Timer interrupt @@ -2486,16 +2490,13 @@ { vortex_t *card = (vortex_t *) codec->private_data; - unsigned long flags; unsigned int lifeboat = 0; - spin_lock_irqsave(&card->lock, flags); /* wait for transactions to clear */ while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { udelay(100); if (lifeboat++ > POLL_COUNT) { printk(KERN_ERR "vortex: ac97 codec stuck busy\n"); - spin_unlock_irqrestore(&card->lock, flags); return; } } @@ -2507,8 +2508,6 @@ /* Flush Caches. */ hwread(card->mmio, VORTEX_CODEC_IO); - - spin_unlock_irqrestore(&card->lock, flags); } static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr) @@ -2516,17 +2515,13 @@ vortex_t *card = (vortex_t *) codec->private_data; u32 read_addr, data; - unsigned long flags; unsigned lifeboat = 0; - spin_lock_irqsave(&card->lock, flags); - /* wait for transactions to clear */ while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { udelay(100); if (lifeboat++ > POLL_COUNT) { printk(KERN_ERR "vortex: ac97 codec stuck busy\n"); - spin_unlock_irqrestore(&card->lock, flags); return 0xffff; } } @@ -2535,20 +2530,15 @@ hwwrite(card->mmio, VORTEX_CODEC_IO, read_addr); /* wait for address */ - { + do { udelay(100); data = hwread(card->mmio, VORTEX_CODEC_IO); if (lifeboat++ > POLL_COUNT) { printk(KERN_ERR "vortex: ac97 address never arrived\n"); - spin_unlock_irqrestore(&card->lock, flags); return 0xffff; } - } - while ((data & VORTEX_CODEC_ADDMASK) != - (addr << VORTEX_CODEC_ADDSHIFT)) ; - - /* Unlock. */ - spin_unlock_irqrestore(&card->lock, flags); + } while ((data & VORTEX_CODEC_ADDMASK) != + (addr << VORTEX_CODEC_ADDSHIFT)); /* return data. */ return (u16) (data & VORTEX_CODEC_DATMASK); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/au88x0/au88x0_pcm.c linux-2.6.10/sound/pci/au88x0/au88x0_pcm.c --- linux.vanilla-2.6.10/sound/pci/au88x0/au88x0_pcm.c 2004-12-25 21:14:49.000000000 +0000 +++ linux-2.6.10/sound/pci/au88x0/au88x0_pcm.c 2005-01-06 19:29:28.000000000 +0000 @@ -206,6 +206,7 @@ printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), params_period_bytes(hw_params), params_channels(hw_params)); */ + spin_lock_irq(&chip->lock); // Make audio routes and config buffer DMA. if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { int dma, type = VORTEX_PCM_TYPE(substream->pcm); @@ -243,6 +244,7 @@ params_periods(hw_params)); } #endif + spin_unlock_irq(&chip->lock); return 0; } @@ -252,6 +254,7 @@ vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) (substream->runtime->private_data); + spin_lock_irq(&chip->lock); // Delete audio routes. if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { if (stream != NULL) @@ -266,6 +269,7 @@ } #endif substream->runtime->private_data = NULL; + spin_unlock_irq(&chip->lock); return snd_pcm_lib_free_pages(substream); } @@ -284,6 +288,7 @@ else dir = 0; fmt = vortex_alsafmt_aspfmt(runtime->format); + spin_lock_irq(&chip->lock); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ , 0); @@ -298,6 +303,7 @@ vortex_wtdma_setstartbuffer(chip, dma, 0); } #endif + spin_unlock_irq(&chip->lock); return 0; } @@ -308,6 +314,7 @@ stream_t *stream = (stream_t *) substream->runtime->private_data; int dma = stream->dma; + spin_lock(&chip->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: // do something to start the PCM engine @@ -355,8 +362,10 @@ #endif break; default: + spin_unlock(&chip->lock); return -EINVAL; } + spin_unlock(&chip->lock); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/azt3328.c linux-2.6.10/sound/pci/azt3328.c --- linux.vanilla-2.6.10/sound/pci/azt3328.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/azt3328.c 2005-01-06 19:29:28.000000000 +0000 @@ -1363,15 +1363,15 @@ for (tmp=0; tmp <= 0x01; tmp += 1) snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); - /* create mixer interface & switches */ - if ((err = snd_azf3328_mixer_new(chip)) < 0) - return err; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_azf3328_free(chip); return err; } + /* create mixer interface & switches */ + if ((err = snd_azf3328_mixer_new(chip)) < 0) + return err; + #if 0 /* set very low bitrate to reduce noise and power consumption? */ snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, 5512, 8, 1); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/cmipci.c linux-2.6.10/sound/pci/cmipci.c --- linux.vanilla-2.6.10/sound/pci/cmipci.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/cmipci.c 2005-01-06 19:29:28.000000000 +0000 @@ -2608,8 +2608,8 @@ if (request_irq(pci->irq, snd_cmipci_interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)cm)) { snd_printk("unable to grab IRQ %d\n", pci->irq); - err = -EBUSY; - goto __error; + snd_cmipci_free(cm); + return -EBUSY; } cm->irq = pci->irq; @@ -2662,6 +2662,11 @@ break; } + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, cm, &ops)) < 0) { + snd_cmipci_free(cm); + return err; + } + /* set MPU address */ switch (iomidi) { case 0x320: val = CM_VMPU_320; break; @@ -2717,22 +2722,22 @@ /* create pcm devices */ pcm_index = pcm_spdif_index = 0; if ((err = snd_cmipci_pcm_new(cm, pcm_index)) < 0) - goto __error; + return err; pcm_index++; if (cm->has_dual_dac) { if ((err = snd_cmipci_pcm2_new(cm, pcm_index)) < 0) - goto __error; + return err; pcm_index++; } if (cm->can_ac3_hw || cm->can_ac3_sw) { pcm_spdif_index = pcm_index; if ((err = snd_cmipci_pcm_spdif_new(cm, pcm_index)) < 0) - goto __error; + return err; } /* create mixer interface & switches */ if ((err = snd_cmipci_mixer_new(cm, pcm_spdif_index)) < 0) - goto __error; + return err; if (iomidi > 0) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, @@ -2742,10 +2747,6 @@ } } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, cm, &ops)) < 0) { - snd_cmipci_free(cm); - return err; - } #ifdef USE_VAR48KRATE for (val = 0; val < ARRAY_SIZE(rates); val++) snd_cmipci_set_pll(cm, rates[val], val); @@ -2785,10 +2786,6 @@ *rcmipci = cm; return 0; - - __error: - snd_cmipci_free(cm); - return err; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/cs4281.c linux-2.6.10/sound/pci/cs4281.c --- linux.vanilla-2.6.10/sound/pci/cs4281.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/cs4281.c 2005-01-06 19:29:28.000000000 +0000 @@ -1439,15 +1439,15 @@ return tmp; } - snd_cs4281_proc_init(chip); - - snd_card_set_pm_callback(card, cs4281_suspend, cs4281_resume, chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_cs4281_free(chip); return err; } + snd_cs4281_proc_init(chip); + + snd_card_set_pm_callback(card, cs4281_suspend, cs4281_resume, chip); + snd_card_set_dev(card, &pci->dev); *rchip = chip; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/cs46xx/cs46xx_lib.c linux-2.6.10/sound/pci/cs46xx/cs46xx_lib.c --- linux.vanilla-2.6.10/sound/pci/cs46xx/cs46xx_lib.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/cs46xx/cs46xx_lib.c 2005-01-06 19:29:28.000000000 +0000 @@ -3866,15 +3866,15 @@ return err; } - snd_cs46xx_proc_init(card, chip); - - snd_card_set_pm_callback(card, snd_cs46xx_suspend, snd_cs46xx_resume, chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_cs46xx_free(chip); return err; } + snd_cs46xx_proc_init(card, chip); + + snd_card_set_pm_callback(card, snd_cs46xx_suspend, snd_cs46xx_resume, chip); + chip->active_ctrl(chip, -1); /* disable CLKRUN */ snd_card_set_dev(card, &pci->dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/ens1370.c linux-2.6.10/sound/pci/ens1370.c --- linux.vanilla-2.6.10/sound/pci/ens1370.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/ens1370.c 2005-01-06 19:29:28.000000000 +0000 @@ -1635,8 +1635,10 @@ if (err < 0) return err; } - if ((ensoniq->subsystem_vendor_id == 0x1274) && - (ensoniq->subsystem_device_id == 0x2000)) { /* GA-7DXR */ + if (((ensoniq->subsystem_vendor_id == 0x1274) && + (ensoniq->subsystem_device_id == 0x2000)) || /* GA-7DXR */ + ((ensoniq->subsystem_vendor_id == 0x1458) && + (ensoniq->subsystem_device_id == 0xa000))) { /* GA-8IEXP */ err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, ensoniq)); if (err < 0) return err; @@ -1930,7 +1932,6 @@ ensoniq->subsystem_vendor_id = cmdw; pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &cmdw); ensoniq->subsystem_device_id = cmdw; - snd_ensoniq_proc_init(ensoniq); #ifdef CHIP1370 #if 0 ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE | ES_1370_PCLKDIVO(ES_1370_SRTODIV(8000)); @@ -2023,6 +2024,8 @@ return err; } + snd_ensoniq_proc_init(ensoniq); + snd_card_set_dev(card, &pci->dev); *rensoniq = ensoniq; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/es1968.c linux-2.6.10/sound/pci/es1968.c --- linux.vanilla-2.6.10/sound/pci/es1968.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/es1968.c 2005-01-06 19:29:28.000000000 +0000 @@ -584,7 +584,7 @@ snd_rawmidi_t *rmidi; spinlock_t reg_lock; - struct semaphore ac97_mutex; /* ac97 lock */ + spinlock_t ac97_lock; struct tasklet_struct hwvol_tq; /* Maestro Stuff */ @@ -686,35 +686,36 @@ static void snd_es1968_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { es1968_t *chip = ac97->private_data; + unsigned long flags; - down(&chip->ac97_mutex); snd_es1968_ac97_wait(chip); /* Write the bus */ + spin_lock_irqsave(&chip->ac97_lock, flags); outw(val, chip->io_port + ESM_AC97_DATA); - msleep(1); + /*msleep(1);*/ outb(reg, chip->io_port + ESM_AC97_INDEX); - msleep(1); - - up(&chip->ac97_mutex); + /*msleep(1);*/ + spin_unlock_irqrestore(&chip->ac97_lock, flags); } static unsigned short snd_es1968_ac97_read(ac97_t *ac97, unsigned short reg) { u16 data = 0; es1968_t *chip = ac97->private_data; + unsigned long flags; - down(&chip->ac97_mutex); snd_es1968_ac97_wait(chip); + spin_lock_irqsave(&chip->ac97_lock, flags); outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); - msleep(1); + /*msleep(1);*/ if (! snd_es1968_ac97_wait(chip)) { data = inw(chip->io_port + ESM_AC97_DATA); - msleep(1); + /*msleep(1);*/ } - up(&chip->ac97_mutex); + spin_unlock_irqrestore(&chip->ac97_lock, flags); return data; } @@ -837,23 +838,19 @@ static void snd_es1968_bob_stop(es1968_t *chip) { u16 reg; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); reg = __maestro_read(chip, 0x11); reg &= ~ESM_BOB_ENABLE; __maestro_write(chip, 0x11, reg); reg = __maestro_read(chip, 0x17); reg &= ~ESM_BOB_START; __maestro_write(chip, 0x17, reg); - spin_unlock_irqrestore(&chip->reg_lock, flags); } static void snd_es1968_bob_start(es1968_t *chip) { int prescale; int divide; - unsigned long flags; /* compute ideal interrupt frequency for buffer size & play rate */ /* first, find best prescaler value to match freq */ @@ -882,13 +879,11 @@ } else if (divide > 1) divide--; - spin_lock_irqsave(&chip->reg_lock, flags); __maestro_write(chip, 6, 0x9000 | (prescale << 5) | divide); /* set reg */ /* Now set IDR 11/17 */ __maestro_write(chip, 0x11, __maestro_read(chip, 0x11) | 1); __maestro_write(chip, 0x17, __maestro_read(chip, 0x17) | 1); - spin_unlock_irqrestore(&chip->reg_lock, flags); } /* call with substream spinlock */ @@ -1931,6 +1926,7 @@ { es1968_t *chip = (es1968_t *) private_data; int x, val; + unsigned long flags; /* Figure out which volume control button was pushed, based on differences from the default register @@ -1945,11 +1941,15 @@ if (! chip->master_switch || ! chip->master_volume) return; - /* FIXME: more clean up is needed.. */ + /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ + spin_lock_irqsave(&chip->ac97_lock, flags); val = chip->ac97->regs[AC97_MASTER]; if (x & 1) { /* mute */ - snd_ac97_write_cache(chip->ac97, AC97_MASTER, val ^ 0x8000); + val ^= 0x8000; + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); } else { @@ -1967,10 +1967,13 @@ if ((val & 0xff00) < 0x1f00) val += 0x0100; } - snd_ac97_write_cache(chip->ac97, AC97_MASTER, val); + chip->ac97->regs[AC97_MASTER] = val; + outw(val, chip->io_port + ESM_AC97_DATA); + outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); } + spin_unlock_irqrestore(&chip->ac97_lock, flags); } /* @@ -2537,7 +2540,7 @@ spin_lock_init(&chip->substream_lock); INIT_LIST_HEAD(&chip->buf_list); INIT_LIST_HEAD(&chip->substream_list); - init_MUTEX(&chip->ac97_mutex); + spin_lock_init(&chip->ac97_lock); init_MUTEX(&chip->memory_mutex); tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); chip->card = card; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/fm801.c linux-2.6.10/sound/pci/fm801.c --- linux.vanilla-2.6.10/sound/pci/fm801.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/fm801.c 2005-01-06 19:29:28.000000000 +0000 @@ -208,15 +208,16 @@ unsigned short mask, unsigned short value) { int change; + unsigned long flags; unsigned short old, new; - spin_lock(&chip->reg_lock); + spin_lock_irqsave(&chip->reg_lock, flags); old = inw(chip->port + reg); new = (old & ~mask) | value; change = old != new; if (change) outw(new, chip->port + reg); - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -415,13 +416,12 @@ static int snd_fm801_playback_prepare(snd_pcm_substream_t * substream) { - unsigned long flags; fm801_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; chip->ply_size = snd_pcm_lib_buffer_bytes(substream); chip->ply_count = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); + spin_lock_irq(&chip->reg_lock); chip->ply_ctrl &= ~(FM801_START | FM801_16BIT | FM801_STEREO | FM801_RATE_MASK | FM801_CHANNELS_MASK); @@ -442,19 +442,18 @@ chip->ply_pos = 0; outl(chip->ply_buffer, FM801_REG(chip, PLY_BUF1)); outl(chip->ply_buffer + (chip->ply_count % chip->ply_size), FM801_REG(chip, PLY_BUF2)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + spin_unlock_irq(&chip->reg_lock); return 0; } static int snd_fm801_capture_prepare(snd_pcm_substream_t * substream) { - unsigned long flags; fm801_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; chip->cap_size = snd_pcm_lib_buffer_bytes(substream); chip->cap_count = snd_pcm_lib_period_bytes(substream); - spin_lock_irqsave(&chip->reg_lock, flags); + spin_lock_irq(&chip->reg_lock); chip->cap_ctrl &= ~(FM801_START | FM801_16BIT | FM801_STEREO | FM801_RATE_MASK); if (snd_pcm_format_width(runtime->format) == 16) @@ -469,7 +468,7 @@ chip->cap_pos = 0; outl(chip->cap_buffer, FM801_REG(chip, CAP_BUF1)); outl(chip->cap_buffer + (chip->cap_count % chip->cap_size), FM801_REG(chip, CAP_BUF2)); - spin_unlock_irqrestore(&chip->reg_lock, flags); + spin_unlock_irq(&chip->reg_lock); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/intel8x0.c linux-2.6.10/sound/pci/intel8x0.c --- linux.vanilla-2.6.10/sound/pci/intel8x0.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/intel8x0.c 2005-01-06 19:29:28.000000000 +0000 @@ -380,6 +380,7 @@ unsigned int ali_slot; /* ALI DMA slot */ struct ac97_pcm *pcm; int pcm_open_flag; + unsigned int page_attr_changed: 1; } ichdev_t; typedef struct _snd_intel8x0 intel8x0_t; @@ -946,13 +947,19 @@ int dbl = params_rate(hw_params) > 48000; int err; - if (chip->fix_nocache && runtime->dma_area && runtime->dma_bytes < size) + if (chip->fix_nocache && ichdev->page_attr_changed) { fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */ + ichdev->page_attr_changed = 0; + } err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; - if (chip->fix_nocache && err > 0) - fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); + if (chip->fix_nocache) { + if (runtime->dma_area && ! ichdev->page_attr_changed) { + fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); + ichdev->page_attr_changed = 1; + } + } if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; @@ -978,8 +985,10 @@ snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; } - if (chip->fix_nocache && substream->runtime->dma_area) + if (chip->fix_nocache && ichdev->page_attr_changed) { fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0); + ichdev->page_attr_changed = 0; + } return snd_pcm_lib_free_pages(substream); } @@ -1743,6 +1752,12 @@ }, { .vendor = 0x1028, + .device = 0x010d, + .name = "Dell", /* which model? AD1885 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .vendor = 0x1028, .device = 0x0126, .name = "Dell Optiplex GX260", /* AD1981A */ .type = AC97_TUNE_HP_ONLY @@ -1753,6 +1768,12 @@ .name = "Dell Precision 450", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, + { + .vendor = 0x1028, + .device = 0x0147, + .name = "Dell", /* which model? AD1981B*/ + .type = AC97_TUNE_HP_ONLY + }, { /* FIXME: which codec? */ .vendor = 0x103c, .device = 0x00c3, @@ -2279,6 +2300,17 @@ for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); + /* clear nocache */ + if (chip->fix_nocache) { + for (i = 0; i < chip->bdbars_count; i++) { + ichdev_t *ichdev = &chip->ichd[i]; + if (ichdev->substream && ichdev->page_attr_changed) { + snd_pcm_runtime_t *runtime = ichdev->substream->runtime; + if (runtime->dma_area) + fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); + } + } + } for (i = 0; i < 3; i++) if (chip->ac97[i]) snd_ac97_suspend(chip->ac97[i]); @@ -2308,7 +2340,7 @@ if (chip->fix_nocache) { for (i = 0; i < chip->bdbars_count; i++) { ichdev_t *ichdev = &chip->ichd[i]; - if (ichdev->substream) { + if (ichdev->substream && ichdev->page_attr_changed) { snd_pcm_runtime_t *runtime = ichdev->substream->runtime; if (runtime->dma_area) fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/korg1212/korg1212.c linux-2.6.10/sound/pci/korg1212/korg1212.c --- linux.vanilla-2.6.10/sound/pci/korg1212/korg1212.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/korg1212/korg1212.c 2005-01-06 19:29:28.000000000 +0000 @@ -2411,14 +2411,17 @@ if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: Reboot Card - RC = %d [%s]\n", rc, stateName[korg1212->cardState]); #endif + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, korg1212, &ops)) < 0) { + snd_korg1212_free(korg1212); + return err; + } + snd_korg1212_EnableCardInterrupts(korg1212); mdelay(CARD_BOOT_DELAY_IN_MS); - if (snd_korg1212_downloadDSPCode(korg1212)) { - snd_korg1212_free(korg1212); + if (snd_korg1212_downloadDSPCode(korg1212)) return -EBUSY; - } printk(KERN_INFO "dspMemPhy = %08x U[%08x]\n" "PlayDataPhy = %08x L[%08x]\n" @@ -2433,10 +2436,8 @@ korg1212->RoutingTablePhy, LowerWordSwap(korg1212->RoutingTablePhy), korg1212->AdatTimeCodePhy, LowerWordSwap(korg1212->AdatTimeCodePhy)); - if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm)) < 0) { - snd_korg1212_free(korg1212); + if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm)) < 0) return err; - } korg1212->pcm->private_data = korg1212; korg1212->pcm->private_free = snd_korg1212_free_pcm; @@ -2453,19 +2454,12 @@ for (i = 0; i < ARRAY_SIZE(snd_korg1212_controls); i++) { err = snd_ctl_add(korg1212->card, snd_ctl_new1(&snd_korg1212_controls[i], korg1212)); - if (err < 0) { - snd_korg1212_free(korg1212); + if (err < 0) return err; - } } snd_korg1212_proc_init(korg1212); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, korg1212, &ops)) < 0) { - snd_korg1212_free(korg1212); - return err; - } - snd_card_set_dev(card, &pci->dev); * rchip = korg1212; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/maestro3.c linux-2.6.10/sound/pci/maestro3.c --- linux.vanilla-2.6.10/sound/pci/maestro3.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/maestro3.c 2005-01-06 19:29:28.000000000 +0000 @@ -2577,26 +2577,7 @@ snd_m3_assp_init(chip); snd_m3_amp_enable(chip, 1); - - if ((err = snd_m3_mixer(chip)) < 0) { - snd_m3_free(chip); - return err; - } - for (i = 0; i < chip->num_substreams; i++) { - m3_dma_t *s = &chip->substreams[i]; - s->chip = chip; - if ((err = snd_m3_assp_client_init(chip, s, i)) < 0) { - snd_m3_free(chip); - return err; - } - } - - if ((err = snd_m3_pcm(chip, 0)) < 0) { - snd_m3_free(chip); - return err; - } - if (request_irq(pci->irq, snd_m3_interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)chip)) { snd_printk("unable to grab IRQ %d\n", pci->irq); @@ -2618,6 +2599,19 @@ return err; } + if ((err = snd_m3_mixer(chip)) < 0) + return err; + + for (i = 0; i < chip->num_substreams; i++) { + m3_dma_t *s = &chip->substreams[i]; + s->chip = chip; + if ((err = snd_m3_assp_client_init(chip, s, i)) < 0) + return err; + } + + if ((err = snd_m3_pcm(chip, 0)) < 0) + return err; + snd_m3_enable_ints(chip); snd_m3_assp_continue(chip); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/nm256/nm256.c linux-2.6.10/sound/pci/nm256/nm256.c --- linux.vanilla-2.6.10/sound/pci/nm256/nm256.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/nm256/nm256.c 2005-01-06 19:29:28.000000000 +0000 @@ -1488,12 +1488,6 @@ snd_nm256_init_chip(chip); - if ((err = snd_nm256_pcm(chip, 0)) < 0) - goto __error; - - if ((err = snd_nm256_mixer(chip)) < 0) - goto __error; - // pci_set_master(pci); /* needed? */ snd_card_set_pm_callback(card, nm256_suspend, nm256_resume, chip); @@ -1614,6 +1608,12 @@ chip->reset_workaround = 1; } + if ((err = snd_nm256_pcm(chip, 0)) < 0 || + (err = snd_nm256_mixer(chip)) < 0) { + snd_card_free(card); + return err; + } + sprintf(card->shortname, "NeoMagic %s", card->driver); sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %d", card->shortname, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/rme9652/hdsp.c linux-2.6.10/sound/pci/rme9652/hdsp.c --- linux.vanilla-2.6.10/sound/pci/rme9652/hdsp.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/rme9652/hdsp.c 2005-01-06 19:29:28.000000000 +0000 @@ -934,6 +934,7 @@ } position &= HDSP_BufferPositionMask; + position /= 4; position &= (hdsp->period_bytes/2) - 1; return position; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/sonicvibes.c linux-2.6.10/sound/pci/sonicvibes.c --- linux.vanilla-2.6.10/sound/pci/sonicvibes.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/sonicvibes.c 2005-01-06 19:29:28.000000000 +0000 @@ -1333,13 +1333,14 @@ #endif sonic->revision = snd_sonicvibes_in(sonic, SV_IREG_REVISION); snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic)); - snd_sonicvibes_proc_init(sonic); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sonic, &ops)) < 0) { snd_sonicvibes_free(sonic); return err; } + snd_sonicvibes_proc_init(sonic); + snd_card_set_dev(card, &pci->dev); *rsonic = sonic; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/trident/trident_main.c linux-2.6.10/sound/pci/trident/trident_main.c --- linux.vanilla-2.6.10/sound/pci/trident/trident_main.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/trident/trident_main.c 2005-01-06 19:29:28.000000000 +0000 @@ -3611,10 +3611,13 @@ return err; } - if ((err = snd_trident_mixer(trident, pcm_spdif_device)) < 0) { + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, trident, &ops)) < 0) { snd_trident_free(trident); return err; } + + if ((err = snd_trident_mixer(trident, pcm_spdif_device)) < 0) + return err; /* initialise synth voices */ for (i = 0; i < 64; i++) { @@ -3635,12 +3638,7 @@ snd_card_set_pm_callback(card, snd_trident_suspend, snd_trident_resume, trident); - snd_trident_proc_init(trident); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, trident, &ops)) < 0) { - snd_trident_free(trident); - return err; - } snd_card_set_dev(card, &pci->dev); *rtrident = trident; return 0; @@ -3650,7 +3648,7 @@ snd_trident_free Description: This routine will free the device specific class for - q the 4DWave card. + the 4DWave card. Paramters: trident - device specific private data for 4DWave card diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/via82xx.c linux-2.6.10/sound/pci/via82xx.c --- linux.vanilla-2.6.10/sound/pci/via82xx.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/via82xx.c 2005-01-06 19:29:28.000000000 +0000 @@ -1635,8 +1635,6 @@ int i, err, caps; unsigned char val; - pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, - chip->old_legacy & ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM)); caps = chip->chip_type == TYPE_VIA8233A ? 1 : 2; for (i = 0; i < caps; i++) { snd_via8233_capture_source.index = i; @@ -1673,7 +1671,6 @@ legacy_cfg = chip->old_legacy_cfg; legacy |= VIA_FUNC_MIDI_IRQMASK; /* FIXME: correct? (disable MIDI) */ legacy &= ~VIA_FUNC_ENABLE_GAME; /* disable joystick */ - legacy &= ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM); /* diable SB & FM */ if (chip->revision >= VIA_REV_686_H) { rev_h = 1; if (mpu_port[dev] >= 0x200) { /* force MIDI */ @@ -2025,6 +2022,8 @@ pci_read_config_byte(pci, VIA_FUNC_ENABLE, &chip->old_legacy); pci_read_config_byte(pci, VIA_PNP_CONTROL, &chip->old_legacy_cfg); + pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, + chip->old_legacy & ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM)); if ((err = pci_request_regions(pci, card->driver)) < 0) { kfree(chip); @@ -2119,6 +2118,7 @@ { .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ + { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ { } /* terminator */ }; struct dxs_whitelist *w; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/vx222/vx222.c linux-2.6.10/sound/pci/vx222/vx222.c --- linux.vanilla-2.6.10/sound/pci/vx222/vx222.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/vx222/vx222.c 2005-01-06 19:29:28.000000000 +0000 @@ -61,8 +61,8 @@ }; static struct pci_device_id snd_vx222_ids[] = { - { 0x10b5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ - { 0x10b5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ + { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ + { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ { 0, } }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/pci/ymfpci/ymfpci_main.c linux-2.6.10/sound/pci/ymfpci/ymfpci_main.c --- linux.vanilla-2.6.10/sound/pci/ymfpci/ymfpci_main.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/pci/ymfpci/ymfpci_main.c 2005-01-06 19:29:28.000000000 +0000 @@ -2265,13 +2265,13 @@ snd_card_set_pm_callback(card, snd_ymfpci_suspend, snd_ymfpci_resume, chip); #endif - snd_ymfpci_proc_init(card, chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_ymfpci_free(chip); return err; } + snd_ymfpci_proc_init(card, chip); + snd_card_set_dev(card, &pci->dev); *rchip = chip; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/ppc/pmac.c linux-2.6.10/sound/ppc/pmac.c --- linux.vanilla-2.6.10/sound/ppc/pmac.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/ppc/pmac.c 2005-01-06 19:29:28.000000000 +0000 @@ -318,7 +318,8 @@ stat = ld_le16(&cp->xfer_status); if (stat & (ACTIVE|DEAD)) { count = in_le16(&cp->res_count); - count = rec->period_size - count; + if (count) + count = rec->period_size - count; } #endif count += rec->cur_period * rec->period_size; @@ -425,10 +426,10 @@ .rate_max = 44100, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = 32768, + .buffer_bytes_max = 131072, .period_bytes_min = 256, .period_bytes_max = 16384, - .periods_min = 1, + .periods_min = 3, .periods_max = PMAC_MAX_FRAGS, }; @@ -444,10 +445,10 @@ .rate_max = 44100, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = 32768, + .buffer_bytes_max = 131072, .period_bytes_min = 256, .period_bytes_max = 16384, - .periods_min = 1, + .periods_min = 3, .periods_max = PMAC_MAX_FRAGS, }; @@ -550,6 +551,8 @@ if (chip->can_duplex) snd_pcm_set_sync(subs); + /* constraints to fix choppy sound */ + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/sound/usb/usbaudio.c linux-2.6.10/sound/usb/usbaudio.c --- linux.vanilla-2.6.10/sound/usb/usbaudio.c 2004-12-25 21:15:54.000000000 +0000 +++ linux-2.6.10/sound/usb/usbaudio.c 2005-01-06 19:29:28.000000000 +0000 @@ -725,7 +725,7 @@ subs->running = 0; if (!force && subs->stream->chip->shutdown) /* to be sure... */ - return 0; + return -EBADFD; async = !can_sleep && async_unlink; @@ -770,6 +770,9 @@ unsigned int i; int err; + if (subs->stream->chip->shutdown) + return -EBADFD; + for (i = 0; i < subs->nurbs; i++) { snd_assert(subs->dataurb[i].urb, return -EINVAL); if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.10/usr/initramfs_list linux-2.6.10/usr/initramfs_list --- linux.vanilla-2.6.10/usr/initramfs_list 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/usr/initramfs_list 2004-12-25 21:23:59.000000000 +0000 @@ -0,0 +1,5 @@ +# This is a very simple initramfs + +dir /dev 0755 0 0 +nod /dev/console 0600 0 0 c 5 1 +dir /root 0700 0 0